Imports System.IO
Imports System.Reflection.Emit
Imports System.Threading
Imports System.Windows.Forms.VisualStyles.VisualStyleElement.TaskbarClock
Imports System.Text
Imports FlexCell
Imports Newtonsoft.Json
Imports System.Data.Common
Imports System.Data.SQLite
Imports System.Net

Public Class Form1

#Region "初始化"

    ''' <summary>
    ''' 项目加载事件
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load

        Me.Text += "(" & Application.ProductVersion & ")"
        If Not String.IsNullOrEmpty(My.Settings.SerialPortName) Then
            My.Settings.Reload()
            ComboBox8.Text = My.Settings.SerialPortName
            ToolStripTextBox1.Text = My.Settings.SInTime
        End If

        '将 和执行文件同目录的CommandSetDic.flx文件拷贝到 C盘C: \NT2406_Tool 下
        '判断C: \NT2406_Tool 存不存在
        If Not IO.Directory.Exists(FileCPatrh) Then
            IO.Directory.CreateDirectory(FileCPatrh)
        End If
        ' 判断文件是否存在($"{Application.StartupPath }\CommandSetDic.flx")
        If IO.File.Exists($"{Application.StartupPath }\CommandSetDic.flx") Then
            '判断文件是否存在
            If IO.File.Exists($"{FileCPatrh}\CommandSetDic.flx") Then

            Else
                '文件拷贝到C: \NT2406_Tool 下
                IO.File.Copy($"{Application.StartupPath }\CommandSetDic.flx", $"{FileCPatrh}\CommandSetDic.flx", True)
            End If

        Else
            MessageBox.Show("CommandSetDic.flx 文件损坏")
            Me.Close()
        End If

        '(FileCPatrh & "\CommandSetDic.flx"

        InitSerialPortBaud()

        Grid_Format_initial()

        Show_Device_Setinfo_Info()

        ClearDeviceform()
        InitGrid_table()
        InitLoadProcessTable()
        InitCommandSetDic()
        ToolStripButton2.PerformClick()
        Timer2.Start()
    End Sub


#End Region


#Region "串口通信"

    ''' <summary>
    ''' 当前时间
    ''' </summary>
    Private _nowTime As Date

    ''' <summary>
    ''' 最后时间
    ''' </summary>
    Private _lastTime As Date

    ''' <summary>
    ''' 时间间隔
    ''' </summary>
    Private _timeInterbval As TimeSpan

    ''' <summary>
    ''' 接收数据偏移量
    ''' </summary>
    Private _recvOffset As Integer

    ''' <summary>
    ''' 接收数据缓存包
    ''' </summary>
    Private _recvBuffer(254) As Byte

    ''' <summary>
    ''' 串口波特率
    ''' </summary>
    Private _baudItme() As String = {"4800", "9600", "14400", "19200", "38400", "56000", "57600", "115200", "256000", "512000", "600000", "750000"}

    Public DbConnString As String = "Server=blv-cloud-db.mysql.rds.aliyuncs.com;Port=3307;Database=blv_productionlinetest;Uid=blv_rcu;Pwd=fnadiaJDIJ7546;charset=utf8;"

    Enum TableEnum
        ID = 0
        测试时间
        测试结果
        测试信息
        RTC时间
        RTC星期
        校准结果
        稳定消抖时间_秒
        背景值滤波长度_秒
        传感器极大值
        传感器极小值
        预热时间_分
        ADC_LEV_10
        ADC_LEV_0
        触发_消抖次数
        释放_消抖次数
        稳定阈值
        报警点提前量
        校准超时_秒
        校准最小值_LEV_0
        校准最小值_LEV_10
        校准最小值_差值
        校准最大值_LEV_0
        校准最大值_LEV_10
        校准最大值_差值
        泄露恢复正常_条件1
        泄露恢复正常_条件2
        泄露恢复正常_条件1消抖时间_秒
        泄露恢复正常_条件2消抖时间_分
        设备生产时间
        软件版本号
        硬件版本号
        设备类型ID
        厂牌ID
        机型ID
        UUID
        状态机
        实时值
        背景值
        基底值
        差值
        LEL百分比
        稳定状态
        基底值差值百分比1
        基底值差值百分比2
        温度
        服务器key
        服务器ClientId
        设备key
        设备ClientId
        MAX
    End Enum

    '获取表格枚举值名称
    Private Function GetTableEnumName(tableEnum As TableEnum) As String
        Return [Enum].GetName(GetType(TableEnum), tableEnum)
    End Function


    ''' <summary>
    ''' 初始化串口波特率
    ''' </summary>
    Private Sub InitSerialPortBaud()
        ComboBox9.Items.Clear()
        ComboBox9.Items.AddRange(_baudItme)
        If ComboBox9.Items.Count > 1 Then ComboBox9.SelectedIndex = 0
    End Sub



    ''' <summary>
    ''' 选择串口
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub ComboBox8_DropDown(sender As Object, e As EventArgs) Handles ComboBox8.DropDown
        GetSerialPort()
    End Sub


    ''' <summary>
    ''' 串口通信
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub Button19_Click(sender As Object, e As EventArgs) Handles Button19.Click

        ' RichTextBox1.Text = Application.ProductName
        If String.IsNullOrWhiteSpace(ComboBox8.Text) Then
            MsgBox($"请先选择有效串口!")
            Exit Sub
        End If
        If String.IsNullOrWhiteSpace(ComboBox9.Text) Then
            MsgBox($"请先选择有效波特率!")
            Exit Sub
        End If

        SerialPortCommSwitch(ComboBox8.Text, ComboBox9.Text)
    End Sub


    ''' <summary>
    ''' 获取可用串口
    ''' </summary>
    Private Sub GetSerialPort()
        Dim portNames As String() = Ports.SerialPort.GetPortNames       '获得可用串口
        Array.Sort(portNames)
        ComboBox8.Items.Clear()
        ComboBox8.Items.AddRange(portNames)
    End Sub


    ''' <summary>
    ''' 串口通讯开关
    ''' </summary>
    ''' <param name="portName"></param>
    ''' <param name="portBaud"></param>
    Private Sub SerialPortCommSwitch(portName As String, portBaud As String)
        If SerialPort.IsOpen Then
            SerialPort.Close()
            CloseSerialPort()
        Else
            ConfigSerialPort(portName, portBaud)
            Try
                SerialPort.Open()
                OpenSerialPort()
            Catch ex As Exception
                'Console.WriteLine($"串口打开失败,原因:{ex.Message}" & vbCrLf, Color.Red)
                MsgBox($"串口打开失败,原因:{ex.Message}")
                SerialPort.Close()
                CloseSerialPort()
            End Try
        End If
    End Sub


    ''' <summary>
    ''' 关闭串口
    ''' </summary>
    Private Sub CloseSerialPort()
        ComboBox8.Enabled = True
        ComboBox9.Enabled = True
        Button19.Text = $"打开串口"
        Button19.ForeColor = Color.Green
    End Sub


    ''' <summary>
    ''' 配置串口
    ''' </summary>
    ''' <param name="portName">串口名</param>
    ''' <param name="portBaud">串口波特率</param>
    Public Sub ConfigSerialPort(portName As String, portBaud As String)
        With SerialPort
            .PortName = portName                '串口名
            .BaudRate = CInt(portBaud)          '波特率
            .DataBits = 8                       '数据位
            .StopBits = Ports.StopBits.One      '停止位
            .Parity = Ports.Parity.Even         '偶校验
            .RtsEnable = True
            .ReceivedBytesThreshold = 1
        End With
    End Sub


    ''' <summary>
    ''' 打开串口
    ''' </summary>
    Private Sub OpenSerialPort()
        ComboBox8.Enabled = False
        ComboBox9.Enabled = False
        Button19.Text = $"关闭串口"
        Button19.ForeColor = Color.Red
    End Sub


    ''' <summary>
    ''' 发送485串口数据
    ''' </summary>
    ''' <param name="dataBuff"></param>
    ''' <returns></returns>
    Private Function SendPortData(dataBuff() As Byte)
        Dim portData As String = ByteToString(dataBuff)
        Dim timeData As String
        Dim cutTime As String

        _nowTime = Now
        _timeInterbval = _nowTime - _lastTime
        _lastTime = _nowTime
        timeData = $"{Math.Round(_timeInterbval.TotalMilliseconds, 0)}"
        timeData = timeData.PadRight(6)
        cutTime = $"{Now:HH:mm:ss:fff}"

        Try
            SerialPort.Write(dataBuff, 0, dataBuff.Length)
            AppendTipText("Com-TX:", Color.Green)
            AppendTipText("(" & cutTime & "-", Color.Black)
            AppendTipText(timeData, Color.BlueViolet)
            AppendTipText("):", Color.Black)
            AppendTipText(portData & vbCrLf, Color.Green)
        Catch ex As Exception
            MsgBox($"串口发送错误！原因:{ex.Message}")
            AppendTipText($"串口发送错误！原因:{ex.Message}", Color.Red)
            Return False
        End Try
        Return True
    End Function

    Private Function SendPortData(dataBuff() As Byte, dataLen As Integer)
        Dim portData As String = ByteToString(dataBuff, dataLen)
        Dim timeData As String
        Dim cutTime As String

        _nowTime = Now
        _timeInterbval = _nowTime - _lastTime
        _lastTime = _nowTime
        timeData = $"{Math.Round(_timeInterbval.TotalMilliseconds, 0)}"
        timeData = timeData.PadRight(6)
        cutTime = $"{Now:HH:mm:ss:fff}"

        Try
            SerialPort.Write(dataBuff, 0, dataLen)
            AppendTipText("Com-TX:", Color.Green)
            AppendTipText("(" & cutTime & "-", Color.Black)
            AppendTipText(timeData, Color.BlueViolet)
            AppendTipText("):", Color.Black)
            AppendTipText(portData & vbCrLf, Color.Green)

        Catch ex As Exception
            MsgBox($"串口发送错误！原因:{ex.Message}")
            AppendTipText($"串口发送错误！原因:{ex.Message}", Color.Red)
            Return False
        End Try
        Return True
    End Function



    ''' <summary>
    ''' 接收485串口数据
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub SerialPort_DataReceived(sender As Object, e As Ports.SerialDataReceivedEventArgs) Handles SerialPort.DataReceived
        Static bytes As Integer
        _recvOffset = 0
        Try
            Do
                bytes = SerialPort.BytesToRead
                If bytes <= 0 Then Exit Sub
                If bytes + _recvOffset >= 255 Then
                    SerialPort.Read(_recvBuffer, _recvOffset, 255 - _recvOffset)
                    ShowPortReceData(_recvBuffer)

                    If IsRuningTest Then
                        ProcessAnalyticalData(_recvBuffer)
                    Else
                        If AnalyticalData(_recvBuffer) = &H1 Then
                            AppendTipText(Encoding.UTF8.GetString(_recvBuffer) & vbCrLf, Color.Green)
                        End If
                    End If

                    _recvOffset = 0
                Else
                    SerialPort.Read(_recvBuffer, _recvOffset, bytes)
                    _recvOffset += bytes
                End If
                Thread.Sleep(10)
            Loop While SerialPort.BytesToRead > 0
            If _recvOffset > 0 Then
                Dim buf(_recvOffset - 1) As Byte
                Array.Copy(_recvBuffer, 0, buf, 0, buf.Length)
                ShowPortReceData(buf)

                If IsRuningTest Then
                    ProcessAnalyticalData(_recvBuffer)
                Else
                    If AnalyticalData(_recvBuffer) = &H1 Then
                        AppendTipText(Encoding.UTF8.GetString(buf) & vbCrLf, Color.Green)
                    End If
                End If

            End If
        Catch ex As Exception
            AppendTipText($"串口接收数据失败,原因:{ex.Message}", Color.Red)
        End Try



    End Sub

    '处理串口接收函数
    Private Function ProcessAnalyticalData(databuff() As Byte) As Byte
        'For Each node In SendNodeDic
        '    If IsRuningTest = False Then Return
        If databuff(0) = &HF0 Then
            If databuff(1) = &HF0 Then
                If databuff(2) = &HF0 Then
                    If databuff(3) = &HF0 Then

                        Dim temp_val As Integer = 0

                        '产品状态
                        Show_Device_Work_State(databuff(4))

                        '浓度状态
                        temp_val = databuff(5)
                        temp_val <<= 8
                        temp_val += databuff(6)

                        'Show_Device_GasMol(temp_val)
                        '寿命状态
                        temp_val = databuff(7)
                        temp_val <<= 8
                        temp_val += databuff(8)

                        'Show_Device_Work_Time(temp_val)

                        '设备时间
                        temp_val = databuff(9)
                        temp_val <<= 8
                        temp_val += databuff(10)
                        temp_val <<= 8
                        temp_val += databuff(11)
                        temp_val <<= 8
                        temp_val += databuff(12)

                        'Show_Device_Present_Time(temp_val)
                        Return &H0
                    Else
                        Return &H1
                    End If
                Else
                    Return &H1
                End If
            Else
                Return &H1
            End If
        ElseIf databuff(0) = &HAE Then
            '设置回复数据
            'Select Case databuff(3)
            '    Case &H1
            '        'AppendTipText("设置成功" & vbCrLf, Color.Blue)
            '        Return &H0
            '    Case &H2
            '        Device_Read_Set_Info_Parsing(databuff)
            '        Return &H0
            '    Case &H3
            '        ' Device_Record_Info_Parsing(databuff)
            '        Return &H0
            'End Select
            SendNodeDicParsing(databuff)
        Else
            Return &H1
        End If

        Return &H1
    End Function

    '枚举SendNodeDic 设置对应数据
    Public isnotSendNode As Boolean = False
    Public IsSetTime As Boolean = False
    Public IsRtcTime As Boolean = False
    Private Sub SendNodeDicParsing(databuff() As Byte)
        Dim node As SendNode
        Dim nextNode As SendNode
        Dim l1, l2 As String
        Dim dt As Date
        Dim buff() As Byte
        Dim ndatabuff(databuff.Length - 1) As Byte
        '拷贝数据到新数组

        Array.Copy(databuff, 0, ndatabuff, 0, ndatabuff.Length)

        For i = 0 To SendNodeDic.Count - 1
            node = SendNodeDic(i).Item2
            If node.SendStatus = SendNode.SendStatusEnum.Send Then
                If node.RecvStatus = SendNode.RecvStatusEnum.None Then
                    If databuff(3) = 2 Then
                        If databuff(3) = node.SendData(3) AndAlso databuff(4) = node.SendData(4) Then
                            node.RecvRefresh(ndatabuff)

                            If databuff(3) = 2 AndAlso databuff(4) = 2 Then
                                If databuff(5) = 0 Then
                                    isnotSendNode = True
                                    'IsRuningTest = False
                                Else
                                    isnotSendNode = False
                                End If

                                If i = SendNodeDic.Count - 2 Then
                                    nextNode = SendNodeDic(i - 1).Item2
                                    If nextNode.SendStatus = SendNode.SendStatusEnum.Send AndAlso
                                nextNode.RecvStatus = SendNode.RecvStatusEnum.Recv AndAlso nextNode.SendData(3) = 1 AndAlso
                                nextNode.SendData(4) = 8 Then
                                        l1 = CombineFourBytesToLong(nextNode.SendData(8), nextNode.SendData(7), nextNode.SendData(6), nextNode.SendData(5))
                                        buff = node.RecvDataLisr(0)
                                        l2 = CombineFourBytesToLong(buff(61), buff(60), buff(59), buff(58))
                                        If l1.Equals(l2) Then
                                            IsSetTime = False
                                        Else
                                            IsSetTime = True
                                            IsRuningTest = False
                                        End If
                                    End If

                                End If




                            End If
                            If databuff(3) = 2 AndAlso databuff(4) = 1 Then
                                If i = SendNodeDic.Count - 1 Then
                                    dt = Date.Parse($"20{Hex2(databuff(6))}-{Hex2(databuff(7))}-{Hex2(databuff(8))} {Hex2(databuff(9))}:{Hex2(databuff(10))}:{Hex2(databuff(11))}")
                                    Dim temp_val As Long = (Now - dt).TotalSeconds
                                    'Console.WriteLine($"RTC时间差 {temp_val}")
                                    If RTC_Time.Year = dt.Year AndAlso RTC_Time.Month = dt.Month AndAlso RTC_Time.Day = dt.Day AndAlso
                                        RTC_Time.Hour = dt.Hour AndAlso RTC_Time.Minute = dt.Minute AndAlso RTC_Time.Second = dt.Second Then
                                        IsRtcTime = True
                                        IsRuningTest = False

                                    Else
                                        If temp_val <= Timediffe Then
                                            IsRtcTime = False
                                        Else
                                            IsRtcTime = True
                                            IsRuningTest = False
                                        End If

                                    End If



                                End If
                            End If



                        End If
                    Else
                        If databuff(3) = node.SendData(3) Then
                            '将数组转字符串比对两个数组是否相等
                            If ByteToString(ndatabuff, node.SendData.Length) = ByteToString(node.SendData, node.SendData.Length) Then
                                Continue For
                            End If
                            node.RecvRefresh(ndatabuff)
                        End If

                    End If

                End If
            End If
        Next
    End Sub


    ''' <summary>
    ''' 显示串口回复数据
    ''' </summary>
    ''' <param name="databuff"></param>
    Private Sub ShowPortReceData(databuff() As Byte)
        Dim portData As String = ByteToString(databuff)
        Dim timeData As String
        Dim cutTime As String

        _nowTime = Now
        _timeInterbval = _nowTime - _lastTime
        _lastTime = _nowTime
        timeData = $"{Math.Round(_timeInterbval.TotalMilliseconds, 0)}"
        timeData = timeData.PadRight(6)
        cutTime = $"{Now:HH:mm:ss:fff}"

        AppendTipText("Com-RX:", Color.Blue)
        AppendTipText("(" & cutTime & "-", Color.Black)
        AppendTipText(timeData, Color.BlueViolet)
        AppendTipText("):", Color.Black)
        AppendTipText(portData & vbCrLf, Color.Blue)
    End Sub


#End Region



#Region "通讯记录"

    ''' <summary>
    ''' 清除记录
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub Button24_Click(sender As Object, e As EventArgs) Handles Button24.Click
        RichTextBox1.Clear()
    End Sub


    ''' <summary>
    ''' 添加记录文本和颜色
    ''' </summary>
    ''' <param name="str">需要添加的记录内容</param>
    ''' <param name="cor">需要设置的记录颜色</param>
    Public Sub AppendTextAndSetStyle(ByVal str As String, ByVal cor As Color)
        Dim selStart As Integer
        Dim selLength As Integer
        selStart = RichTextBox1.TextLength
        RichTextBox1.AppendText(str)
        selLength = RichTextBox1.TextLength - selStart
        RichTextBox1.Select(selStart, selLength)
        RichTextBox1.SelectionColor = cor
    End Sub


    ''' <summary>
    ''' 添加记录
    ''' </summary>
    ''' <param name="recordString"></param>
    ''' <param name="col"></param>
    Public Sub AppendTipText(recordString As String, col As Color)
        If RichTextBox1.InvokeRequired Then
            RichTextBox1.Invoke(New Action(Sub()
                                               If RichTextBox1.Lines.Count >= 256 Then RichTextBox1.Clear()
                                               AppendTextAndSetStyle($"{recordString}", col)
                                               RichTextBox1.ScrollToCaret()
                                           End Sub))
        Else
            If RichTextBox1.Lines.Count >= 256 Then RichTextBox1.Clear()
            AppendTextAndSetStyle($"{recordString}", col)
            RichTextBox1.ScrollToCaret()
        End If
    End Sub



#End Region



#Region "解析串口数据"

    ''' <summary>
    ''' 解析串口数据
    ''' </summary>
    ''' <param name="databuff"></param>
    Private Function AnalyticalData(databuff() As Byte) As Byte


        If databuff(0) = &HF0 Then
            If databuff(1) = &HF0 Then
                If databuff(2) = &HF0 Then
                    If databuff(3) = &HF0 Then

                        Dim temp_val As Integer = 0

                        '产品状态
                        Show_Device_Work_State(databuff(4))

                        '浓度状态
                        temp_val = databuff(5)
                        temp_val <<= 8
                        temp_val += databuff(6)

                        Show_Device_GasMol(temp_val)
                        '寿命状态
                        temp_val = databuff(7)
                        temp_val <<= 8
                        temp_val += databuff(8)

                        Show_Device_Work_Time(temp_val)

                        '设备时间
                        temp_val = databuff(9)
                        temp_val <<= 8
                        temp_val += databuff(10)
                        temp_val <<= 8
                        temp_val += databuff(11)
                        temp_val <<= 8
                        temp_val += databuff(12)

                        Show_Device_Present_Time(temp_val)
                        Return &H0
                    Else
                        Return &H1
                    End If
                Else
                    Return &H1
                End If
            Else
                Return &H1
            End If
        ElseIf databuff(0) = &HAE Then
            '设置回复数据
            Select Case databuff(3)
                Case &H1
                    AppendTipText("设置成功" & vbCrLf, Color.Blue)
                    Return &H0
                Case &H2
                    Device_Read_Set_Info_Parsing(databuff)
                    Return &H0
                Case &H3
                    Device_Record_Info_Parsing(databuff)
                    Return &H0
            End Select

        Else
            Return &H1
        End If

        Return &H1
    End Function

    ''' <summary>
    ''' Byte数组转字符串
    ''' </summary>
    ''' <param name="databuff"></param>
    ''' <returns></returns>
    Public Function ByteToString(databuff() As Byte)
        Dim strData As String = String.Empty
        For i = 0 To databuff.Length - 1
            strData &= $" {Hex(databuff(i)).PadLeft(2, "0"c)}"
        Next
        Return strData
    End Function

    Public Function ByteToString(databuff() As Byte, dataLen As Integer)
        Dim strData As String = String.Empty
        For i = 0 To dataLen - 1
            strData &= $" {Hex(databuff(i)).PadLeft(2, "0"c)}"
        Next
        Return strData
    End Function

#End Region


#Region "设置读取信息"

    ''' <summary>
    ''' 读取核心参数信息-委托
    ''' </summary>
    Delegate Sub RefreshState_Show(state As Byte)
    Delegate Sub RefreshVal_Show(state As Integer)
    Delegate Sub RefreBuff_Show(buff() As Byte)

    Public Sub Show_Device_Setinfo_Info()

        '稳定消抖时间 - 单位：s
        TextBox6.Text = "30"

        '背景值滤波长度 - 最大：300S
        TextBox13.Text = "300"

        '传感器极大值
        TextBox7.Text = "3500"

        '传感器极小值
        TextBox8.Text = "500"

        '预热时间 - 单位：分钟
        TextBox14.Text = "3"

        'LEV 10% 对应的ADC 值
        TextBox1.Text = "2800"

        'LEV 0%  对应的ADC 值
        TextBox2.Text = "1000"

        '触发 - 消抖次数
        TextBox3.Text = "150"

        '释放 - 消抖次数
        TextBox4.Text = "150"

        '稳定阈值
        TextBox5.Text = "30"

        '报警点提前量
        TextBox11.Text = "100"

        '校准超时 - 单位：S
        TextBox12.Text = "180"

        '校准0% LEL 下限
        TextBox15.Text = "100"

        '校准0% LEL 上限
        TextBox16.Text = "2200"

        '校准10% LEL 下限
        TextBox19.Text = "1000"

        '校准10% LEL 上限
        TextBox20.Text = "3400"

        '校准差值 下限
        TextBox17.Text = "1000"

        '校准差值 上限
        TextBox18.Text = "2500"

        '泄露恢复至正常 条件1：稳定处于基准值的多少倍以内，且达到消抖次数多少秒
        TextBox21.Text = "1.2"          '基准倍数
        TextBox22.Text = "5"            '消抖时间

        '泄露恢复至正常 条件2：稳定处于基准值的多少倍以内，且持续时间超过多少分钟
        TextBox23.Text = "1.5"          '基准倍数
        TextBox24.Text = "120"          '消抖时间

    End Sub

    ''' <summary>
    ''' 显示开关状态
    ''' </summary>
    ''' <param name="state"></param>
    Public Sub Show_Device_Work_State(state As Byte)

        If InvokeRequired = True Then
            Dim dev As New RefreshState_Show(AddressOf Show_Device_Work_State)
            Me.Invoke(dev, New Object() {state})
        Else
            Select Case state
                Case &H2F
                    Lab_DeviceState.ForeColor = Color.Orange
                    Lab_DeviceState.Text = "预热"

                Case &HB
                    Lab_DeviceState.ForeColor = Color.Green
                    Lab_DeviceState.Text = "正常"

                Case &H48
                    Lab_DeviceState.ForeColor = Color.Red
                    Lab_DeviceState.Text = "报警"
            End Select
        End If

    End Sub

    ''' <summary>
    ''' 显示设备浓度
    ''' </summary>
    ''' <param name="mol"></param>
    Public Sub Show_Device_GasMol(mol As Integer)
        If InvokeRequired = True Then
            Dim dev As New RefreshVal_Show(AddressOf Show_Device_GasMol)
            Me.Invoke(dev, New Object() {mol})
        Else
            Lab_mol.ForeColor = Color.Black
            Lab_mol.Text = mol.ToString & " mV"
        End If


    End Sub

    ''' <summary>
    ''' 显示工作天数
    ''' </summary>
    ''' <param name="day"></param>
    Public Sub Show_Device_Work_Time(day As Integer)
        If InvokeRequired = True Then
            Dim dev As New RefreshVal_Show(AddressOf Show_Device_Work_Time)
            Me.Invoke(dev, New Object() {day})
        Else
            Lab_WorkTime.ForeColor = Color.Black
            Lab_WorkTime.Text = day.ToString & " 天"
        End If
    End Sub

    ''' <summary>
    ''' 显示当前时间
    ''' </summary>
    ''' <param name="time"></param>
    Public Sub Show_Device_Present_Time(time As Integer)

        If InvokeRequired = True Then
            Dim dev As New RefreshVal_Show(AddressOf Show_Device_Present_Time)
            Me.Invoke(dev, New Object() {time})
        Else
            Dim dateTimeOffset As DateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(time)

            Dim localTime As DateTime = dateTimeOffset.LocalDateTime

            Lab_DeviceTime.Text = localTime.ToString("yyyy-MM-dd HH:mm:ss")
        End If

    End Sub
    ''' <summary>
    ''' 将 Int32 转为 4 字节数组，低字节在前。
    ''' </summary>
    Public Function IntTo4BytesLE(value As Integer) As Byte()
        Return BitConverter.GetBytes(value) ' BitConverter 在 Windows/Intel 就是 Little-Endian
    End Function
    ''' <summary>
    ''' Int转2个字节Byte
    ''' 高字节在前,低字节在后
    ''' </summary>
    ''' <param name="i"></param>
    ''' <returns></returns>
    Public Function IntToByteHB(ByVal i As Integer) As Byte()
        Dim btemp() As Byte = {0, 0}
        Dim b() As Byte = BitConverter.GetBytes(i)
        btemp(0) = b(0)
        btemp(1) = b(1)
        Return btemp
    End Function

    ''' <summary>
    ''' 和校验取余数
    ''' 求Byte数组的和校验取余数
    ''' </summary>
    ''' <param name="dataPacket">Byte数组</param>
    ''' <returns></returns>
    Public Function GetSumCheckMod(dataPacket As Byte()) As Byte
        Dim sum As Integer
        For idx = 0 To dataPacket.Length - 1
            sum += dataPacket(idx)
            sum = sum And &HFF
        Next
        Dim sumMod As Byte = &HFF - sum
        Return sumMod
    End Function

    Public Function GetSumCheckMod(dataPacket As Byte(), dataLen As Integer) As Byte
        Dim sum As Integer
        For idx = 0 To dataLen - 1
            sum += dataPacket(idx)
            sum = sum And &HFF
        Next
        Dim sumMod As Byte = &HFF - sum
        Return sumMod
    End Function

    Public Sub Show_Device_ReadRtc(buff() As Byte)

        If InvokeRequired = True Then
            Dim dev As New RefreBuff_Show(AddressOf Show_Device_ReadRtc)
            Me.Invoke(dev, New Object() {buff})
        Else

            DateTimePicker1.Value = New DateTime(CInt($"20{Hex(buff(6))}"), CInt($"{Hex(buff(7))}"), CInt($"{Hex(buff(8))}"), CInt($"{Hex(buff(9))}"), CInt($"{Hex(buff(10))}"), CInt($"{Hex(buff(11))}"))

        End If

    End Sub

    Public Function ConvertUtcTimestampToDateTime(timestamp As Long) As DateTime
        ' 创建一个 DateTime 对象，表示从 Unix 时间戳转换而来的时间
        Dim unixEpoch As New DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)

        ' 添加时间戳所表示的秒数
        Dim convertedDateTime As DateTime = unixEpoch.AddSeconds(timestamp)

        ' 返回本地时间
        Return convertedDateTime.ToLocalTime()
    End Function

    Public Sub Show_Device_SetInfo(buff() As Byte)

        If InvokeRequired = True Then
            Dim dev As New RefreBuff_Show(AddressOf Show_Device_SetInfo)
            Me.Invoke(dev, New Object() {buff})
        Else

            Dim temp_val As Integer
            Dim temp_len As Integer = 6

            '稳定消抖时间 - 单位：s
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox6.Text = temp_val.ToString
            AppendTipText($"报警电压 ： {temp_val}" & vbCrLf, Color.Blue)

            '背景值滤波长度 - 最大：600S
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox13.Text = temp_val.ToString
            AppendTipText($"报警电压 ： {temp_val}" & vbCrLf, Color.Blue)

            '传感器极大值
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox7.Text = temp_val.ToString
            AppendTipText($"报警电压 ： {temp_val}" & vbCrLf, Color.Blue)

            '传感器极小值
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox8.Text = temp_val.ToString
            AppendTipText($"报警电压 ： {temp_val}" & vbCrLf, Color.Blue)

            '预热时间 - 单位：分钟
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox14.Text = temp_val.ToString
            AppendTipText($"报警电压 ： {temp_val}" & vbCrLf, Color.Blue)

            'LEV 10% 对应的ADC 值
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox1.Text = temp_val.ToString
            AppendTipText($"报警电压 ： {temp_val}" & vbCrLf, Color.Blue)

            'LEV 0%  对应的ADC 值
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox2.Text = temp_val.ToString
            AppendTipText($"报警电压 ： {temp_val}" & vbCrLf, Color.Blue)

            '触发 - 消抖次数
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox3.Text = temp_val.ToString
            AppendTipText($"报警电压 ： {temp_val}" & vbCrLf, Color.Blue)

            '释放 - 消抖次数
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox4.Text = temp_val.ToString
            AppendTipText($"报警电压 ： {temp_val}" & vbCrLf, Color.Blue)

            '稳定阈值
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox5.Text = temp_val.ToString
            AppendTipText($"报警电压 ： {temp_val}" & vbCrLf, Color.Blue)

            '报警点提前量
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox11.Text = temp_val.ToString
            AppendTipText($"报警电压 ： {temp_val}" & vbCrLf, Color.Blue)

            '校准超时 - 单位：S
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox12.Text = temp_val.ToString
            AppendTipText($"报警电压 ： {temp_val}" & vbCrLf, Color.Blue)

            '校准0% LEL 下限
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox15.Text = temp_val.ToString
            AppendTipText($"校准0% LEL 下限 ： {temp_val}" & vbCrLf, Color.Blue)

            '校准0% LEL 上限
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox16.Text = temp_val.ToString
            AppendTipText($"校准0% LEL 下限 ： {temp_val}" & vbCrLf, Color.Blue)

            '校准10% LEL 下限
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox19.Text = temp_val.ToString
            AppendTipText($"校准10% LEL 下限 ： {temp_val}" & vbCrLf, Color.Blue)

            '校准10% LEL 上限
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox20.Text = temp_val.ToString
            AppendTipText($"校准10% LEL 下限 ： {temp_val}" & vbCrLf, Color.Blue)

            '校准差值 下限
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox17.Text = temp_val.ToString
            AppendTipText($"校准0% LEL 下限 ： {temp_val}" & vbCrLf, Color.Blue)

            '校准差值 上限
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox18.Text = temp_val.ToString
            AppendTipText($"校准0% LEL 下限 ： {temp_val}" & vbCrLf, Color.Blue)

            '泄露条件1 - 基准值的倍数
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            Dim temp_mult As Double = temp_val / 10
            TextBox21.Text = temp_mult.ToString
            AppendTipText($"泄露条件1 - 基准值的 {temp_mult}倍数" & vbCrLf, Color.Blue)

            '泄露条件1 - 消抖时间
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox22.Text = temp_val.ToString
            AppendTipText($"泄露条件1 - 消抖时间： {temp_val}S" & vbCrLf, Color.Blue)

            '泄露条件2 - 基准值的倍数
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            temp_mult = temp_val / 10
            TextBox23.Text = temp_mult.ToString
            AppendTipText($"泄露条件2 - 基准值的 {temp_mult}倍数" & vbCrLf, Color.Blue)

            '泄露条件2 - 消抖时间
            temp_val = buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            temp_len += 2
            TextBox24.Text = temp_val.ToString
            AppendTipText($"泄露条件2 - 消抖时间： {temp_val}Min" & vbCrLf, Color.Blue)

            '生产时间戳
            temp_val = buff(temp_len + 3)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len + 2)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len + 1)
            temp_val <<= 8
            temp_val = temp_val Or buff(temp_len)
            DateTimeP_RelDate.Value = ConvertUtcTimestampToDateTime(temp_val)
            AppendTipText($"生产时间 ：" & DateTimeP_RelDate.Value & vbCrLf, Color.Blue)


        End If

    End Sub

    Public Sub Device_Read_Set_Info_Parsing(buff As Byte())
        Select Case buff(4)
            Case &H1
                If buff(5) = &H0 Then
                    AppendTipText("读取RTC时间成功" & vbCrLf, Color.Blue)

                    AppendTipText($"RTC: 20{Hex(buff(6))}-{Hex(buff(7))}-{Hex(buff(8))} {Hex(buff(9))}:{Hex(buff(10))}:{Hex(buff(11))} {Hex(buff(12))} " & vbCrLf, Color.Blue)
                    Show_Device_ReadRtc(buff)
                Else
                    AppendTipText("读取RTC时间失败" & vbCrLf, Color.Red)

                End If

            Case &H2
                If buff(5) = &H0 Then
                    AppendTipText("读取 设置参数 成功" & vbCrLf, Color.Blue)
                    Show_Device_SetInfo(buff)
                Else
                    AppendTipText("读取 设置参数 失败" & vbCrLf, Color.Blue)
                End If

        End Select

    End Sub

    Public Sub Device_LogInfo_Data_Parsing(data As Integer)

        If InvokeRequired = True Then
            Dim dev As New RefreshVal_Show(AddressOf Device_LogInfo_Data_Parsing)
            Me.Invoke(dev, New Object() {data})
        Else
            TextBox9.Text = data.ToString()

        End If

    End Sub

    Public Sub Device_Log_Data_Parsing(buff As Byte())

        If InvokeRequired = True Then
            Dim dev As New RefreBuff_Show(AddressOf Device_Log_Data_Parsing)
            Me.Invoke(dev, New Object() {buff})
        Else

            If buff(0) = &H1A And buff(2) = &HE Then
                If GetSumCheckMod(buff, &HE) = &H0 Then

                    Dim temp_rtc_tick As Integer
                    Dim temp_val As Integer
                    Dim log_temp_data As New LOG_Data_List

                    log_temp_data.sn = buff(1)

                    temp_rtc_tick = buff(4)
                    temp_rtc_tick <<= 8
                    temp_rtc_tick = temp_rtc_tick Or buff(5)
                    temp_rtc_tick <<= 8
                    temp_rtc_tick = temp_rtc_tick Or buff(6)
                    temp_rtc_tick <<= 8
                    temp_rtc_tick = temp_rtc_tick Or buff(7)

                    log_temp_data.time = ConvertUtcTimestampToDateTime(temp_rtc_tick)
                    AppendTipText($"LOG ：" & log_temp_data.time & vbCrLf, Color.Blue)

                    log_temp_data.type = buff(8)

                    Select Case buff(8)
                        Case &H1
                            AppendTipText($"记录类型 - 浓度报警记录" & vbCrLf, Color.Blue)
                            temp_rtc_tick = buff(9)
                            temp_rtc_tick <<= 8
                            temp_rtc_tick = temp_rtc_tick Or buff(10)
                            log_temp_data.parsing = $"浓度报警  {temp_rtc_tick}  {buff(12)}%   {buff(11)}℃"
                        Case &H2
                            AppendTipText($"记录类型 - 浓度恢复记录" & vbCrLf, Color.Blue)
                            temp_rtc_tick = buff(9)
                            temp_rtc_tick <<= 8
                            temp_rtc_tick = temp_rtc_tick Or buff(10)
                            log_temp_data.parsing = $"浓度恢复  {temp_rtc_tick}  {buff(12)}%  {buff(11)}℃"
                        Case &H3
                            AppendTipText($"记录类型 - 产品故障记录" & vbCrLf, Color.Blue)
                            log_temp_data.parsing = $"产品故障  {buff(9)}  {buff(11)}℃"
                        Case &H4
                            AppendTipText($"记录类型 - 产品故障恢复记录" & vbCrLf, Color.Blue)
                            log_temp_data.parsing = $"产品故障恢复   {buff(9)}  {buff(11)}℃"
                        Case &H5
                            AppendTipText($"记录类型 - 产品上电记录" & vbCrLf, Color.Blue)
                            log_temp_data.parsing = $"产品上电 "
                        Case &H6
                            AppendTipText($"记录类型 - 产品断电记录" & vbCrLf, Color.Blue)
                            log_temp_data.parsing = $"产品断电 "
                        Case &H7
                            AppendTipText($"记录类型 - 传感器失效记录" & vbCrLf, Color.Blue)
                            log_temp_data.parsing = $"传感器失效 "

                        Case &H8
                            AppendTipText($"记录类型 - 传感器校准记录" & vbCrLf, Color.Blue)
                            temp_rtc_tick = buff(9)
                            temp_rtc_tick <<= 8
                            temp_rtc_tick = temp_rtc_tick Or buff(10)

                            temp_val = buff(11)
                            temp_val <<= 8
                            temp_val = temp_val Or buff(12)
                            log_temp_data.parsing = $"传感器校准  LEL_0:{temp_rtc_tick}  LEL_10:{temp_val}"

                    End Select

                    '将解析后的数据添加到列表中
                    Dim log_sn As Integer = CInt(TextBox10.Text)

                    'Console.WriteLine($"Log sn:{log_sn} - {Log_Data.Count}")
                    If Log_Data.Count > log_sn Then
                        Log_Data(log_sn) = log_temp_data
                        Grid_Refresh_LOG_Data(Log_Data, log_sn + 1, Grid1)

                        'Console.WriteLine($"Refresh_LOG_Data ")
                    Else

                        Log_Data.Add(log_temp_data)
                        Grid_ADD_LOG_Data(Log_Data, Grid1)

                        'Console.WriteLine($"Add new line ")
                    End If

                End If
            End If
        End If

    End Sub




    Public Sub Device_Record_Info_Parsing(buff As Byte())
        Select Case buff(4)
            Case &H0
                If buff(5) = &H0 Then
                    AppendTipText("读取成功" & vbCrLf, Color.Blue)

                    Dim Log_num As Integer
                    Dim log_addr As Integer

                    Log_num = buff(6)
                    Log_num <<= 8
                    Log_num += buff(7)

                    log_addr = buff(8)
                    log_addr <<= 8
                    log_addr += buff(9)
                    log_addr <<= 8
                    log_addr += buff(10)
                    log_addr <<= 8
                    log_addr += buff(11)

                    AppendTipText($"日志数量：{Log_num} 日志地址：{Hex(log_addr)}" & vbCrLf, Color.Blue)

                    Device_LogInfo_Data_Parsing(Log_num)
                Else
                    AppendTipText("读取失败" & vbCrLf, Color.Blue)
                End If

            Case &H1
                If buff(5) = &H0 Then
                    AppendTipText("读取日志成功" & vbCrLf, Color.Blue)

                    Dim log_data(100) As Byte
                    Dim log_len As Byte = buff(1) - 7
                    Array.Copy(buff, 6, log_data, 0, log_len)

                    AppendTipText("读取日志数据 ：" & ByteToString(log_data, log_len) & vbCrLf, Color.Blue)

                    Device_Log_Data_Parsing(log_data)

                Else
                    AppendTipText("读取日志失败" & vbCrLf, Color.Blue)
                End If


        End Select
    End Sub

    Private Sub But_SetRTCTime_Click(sender As Object, e As EventArgs) Handles But_SetRTCTime.Click
        Dim send_data(20) As Byte

        send_data(0) = &HAE     '包头
        send_data(1) = 13     '长度
        send_data(2) = &H0     '校验
        send_data(3) = &H1     '命令 - 设置参数
        send_data(4) = &H1     '参数内容 - 设置RTC时间

        If CheckBox2.Checked = True Then
            '使用系统时间
            send_data(5) = $"&H{Now.Date.Year Mod 100}"
            send_data(6) = $"&H{Now.Date.Month Mod 100}"
            send_data(7) = $"&H{Now.Date.Day Mod 100}"
            send_data(8) = $"&H{Now.Hour}"
            send_data(9) = $"&H{Now.Minute }"
            send_data(10) = $"&H{Now.Second }"
            send_data(11) = $"&H{Now.Date.DayOfWeek Mod 100}"
        Else
            '自定义时间
            send_data(5) = $"&H{DateTimePicker1.Value.Year Mod 100}"
            send_data(6) = $"&H{DateTimePicker1.Value.Month Mod 100}"
            send_data(7) = $"&H{DateTimePicker1.Value.Day Mod 100}"
            send_data(8) = $"&H{DateTimePicker1.Value.Hour}"
            send_data(9) = $"&H{DateTimePicker1.Value.Minute }"
            send_data(10) = $"&H{DateTimePicker1.Value.Second }"
            send_data(11) = $"&H{DateTimePicker1.Value.DayOfWeek Mod 100}"
        End If


        send_data(12) = &HEA      '包尾

        send_data(2) = GetSumCheckMod(send_data, 13)

        SendPortData(send_data, 13)

    End Sub
    Public Function GetSetRTCTime() As Byte()
        Dim send_data(12) As Byte

        send_data(0) = &HAE     '包头
        send_data(1) = 13     '长度
        send_data(2) = &H0     '校验
        send_data(3) = &H1     '命令 - 设置参数
        send_data(4) = &H1     '参数内容 - 设置RTC时间
        RTC_Time = Now
        If CheckBox2.Checked = True Then
            '使用系统时间
            send_data(5) = $"&H{RTC_Time.Date.Year Mod 100}"
            send_data(6) = $"&H{RTC_Time.Date.Month Mod 100}"
            send_data(7) = $"&H{RTC_Time.Date.Day Mod 100}"
            send_data(8) = $"&H{RTC_Time.Hour}"
            send_data(9) = $"&H{RTC_Time.Minute }"
            send_data(10) = $"&H{RTC_Time.Second }"
            send_data(11) = $"&H{RTC_Time.Date.DayOfWeek Mod 100}"
        Else
            '自定义时间
            send_data(5) = $"&H{DateTimePicker1.Value.Year Mod 100}"
            send_data(6) = $"&H{DateTimePicker1.Value.Month Mod 100}"
            send_data(7) = $"&H{DateTimePicker1.Value.Day Mod 100}"
            send_data(8) = $"&H{DateTimePicker1.Value.Hour}"
            send_data(9) = $"&H{DateTimePicker1.Value.Minute }"
            send_data(10) = $"&H{DateTimePicker1.Value.Second }"
            send_data(11) = $"&H{DateTimePicker1.Value.DayOfWeek Mod 100}"
        End If

        send_data(12) = &HEA      '包尾

        send_data(2) = GetSumCheckMod(send_data, 13)
        Return send_data
    End Function

    Public Function GetSetUTCTime() As Byte()
        Dim send_data(9) As Byte

        send_data(0) = &HAE     '包头
        send_data(1) = 10     '长度
        send_data(2) = &H0     '校验
        send_data(3) = &H1     '命令 - 设置参数
        send_data(4) = &H8     '参数内容 - 设置RTC时间

        '获取到秒的UTC时间戳
        Dim Utc As Integer = CInt((DateTime.Now - New DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds)
        '将UTC时间戳转换为字节数组
        Dim UtcBytes As Byte() = BitConverter.GetBytes(Utc)
        send_data(5) = UtcBytes(0)
        send_data(6) = UtcBytes(1)
        send_data(7) = UtcBytes(2)
        send_data(8) = UtcBytes(3)
        send_data(9) = &HEA      '包尾

        send_data(2) = GetSumCheckMod(send_data, 10)
        Return send_data
    End Function


    Private Sub But_ReleaseDate_Click(sender As Object, e As EventArgs) Handles But_ReleaseDate.Click
        Dim send_data(100) As Byte
        Dim temp_len As Integer = 0

        send_data(0) = &HAE    '包头
        send_data(1) = 29      '长度
        send_data(2) = &H0     '校验
        send_data(3) = &H1     '命令 - 设置参数
        send_data(4) = &H2     '参数内容 - 设置出厂时间及参数信息
        temp_len += 5
        Dim unixEpoch As New DateTime(1970, 1, 1, 8, 0, 0, DateTimeKind.Utc)
        Dim utcTime As Integer
        Dim temp_buff() As Byte

        '稳定消抖时间 - 单位:S
        temp_buff = BitConverter.GetBytes(CInt(TextBox6.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '背景值滤波长度 - 最大：600S
        temp_buff = BitConverter.GetBytes(CInt(TextBox13.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '传感器极大值 - 最大：4095
        temp_buff = BitConverter.GetBytes(CInt(TextBox7.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '传感器极小值 - 最大：3000
        temp_buff = BitConverter.GetBytes(CInt(TextBox8.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '预热时间 - 单位：分钟
        temp_buff = BitConverter.GetBytes(CInt(TextBox14.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        'LEV 10% 对应的ADC 值
        temp_buff = BitConverter.GetBytes(CInt(TextBox1.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        'LEV 0% 对应的ADC 值
        temp_buff = BitConverter.GetBytes(CInt(TextBox2.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '触发 - 消抖次数
        temp_buff = BitConverter.GetBytes(CInt(TextBox3.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '释放 - 消抖次数
        temp_buff = BitConverter.GetBytes(CInt(TextBox4.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '稳定阈值
        temp_buff = BitConverter.GetBytes(CInt(TextBox5.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '报警点提前量
        temp_buff = BitConverter.GetBytes(CInt(TextBox11.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '校准超时 - 单位：S
        temp_buff = BitConverter.GetBytes(CInt(TextBox12.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '校准0% LEL下限 - 
        temp_buff = BitConverter.GetBytes(CInt(TextBox15.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '校准0% LEL上限 - 
        temp_buff = BitConverter.GetBytes(CInt(TextBox16.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '校准10% LEL下限 - 
        temp_buff = BitConverter.GetBytes(CInt(TextBox19.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '校准10% LEL上限 - 
        temp_buff = BitConverter.GetBytes(CInt(TextBox20.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '校准差值下限
        temp_buff = BitConverter.GetBytes(CInt(TextBox17.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '校准差值上限
        temp_buff = BitConverter.GetBytes(CInt(TextBox18.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '恢复正常模式，条件1：基准倍数 扩大10倍进行数据下发
        Dim temp_mult As Integer = (CDbl(TextBox21.Text) * 10)
        temp_buff = BitConverter.GetBytes(temp_mult)
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '恢复正常模式，条件1：消抖时间
        temp_buff = BitConverter.GetBytes(CInt(TextBox22.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '恢复正常模式，条件2：基准倍数 扩大10倍进行数据下发
        temp_mult = (CDbl(TextBox23.Text) * 10)
        temp_buff = BitConverter.GetBytes(temp_mult)
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '恢复正常模式，条件2：消抖时间
        temp_buff = BitConverter.GetBytes(CInt(TextBox24.Text))
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1

        '设备出厂时间
        utcTime = CInt((DateTimeP_RelDate.Value - unixEpoch).TotalSeconds)
        'Console.WriteLine("DateTimeP_RelDate UTC时间: " & utcTime)
        temp_buff = BitConverter.GetBytes(utcTime)
        send_data(temp_len) = temp_buff(0)
        temp_len += 1
        send_data(temp_len) = temp_buff(1)
        temp_len += 1
        send_data(temp_len) = temp_buff(2)
        temp_len += 1
        send_data(temp_len) = temp_buff(3)
        temp_len += 1

        send_data(temp_len) = &HEA      '包尾
        temp_len += 1

        send_data(1) = temp_len      '长度
        send_data(2) = GetSumCheckMod(send_data, temp_len)

        SendPortData(send_data, temp_len)

    End Sub

    Public Function Judge_Volt_Range(sender As Object, e As EventArgs) As Byte
        Dim rev As Byte
        Dim temp_obj As TextBox = sender

        If temp_obj.TextLength > 0 AndAlso CUInt(temp_obj.Text) > 4096 Then
            temp_obj.Text = 4095
            MsgBox($"超出范围:{CUInt(temp_obj.Text)} 输入范围：0~4095")
        ElseIf temp_obj.TextLength = 0 Then
            temp_obj.Text = 0
        End If

        Return rev
    End Function

    Public Function Judge_Debounce_Range(sender As Object, e As EventArgs) As Byte
        Dim rev As Byte
        Dim temp_obj As TextBox = sender

        If temp_obj.TextLength > 0 AndAlso CUInt(temp_obj.Text) > 5000 Then
            temp_obj.Text = 4999
            MsgBox($"超出范围:{CUInt(temp_obj.Text)} 输入范围：0~4999")
        ElseIf temp_obj.TextLength = 0 Then
            temp_obj.Text = 0
        End If

        Return rev
    End Function

    Private Sub TBox_Volt_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged, TextBox5.TextChanged, TextBox2.TextChanged, TextBox11.TextChanged, TextBox13.TextChanged, TextBox12.TextChanged, TextBox7.TextChanged, TextBox20.TextChanged, TextBox19.TextChanged, TextBox18.TextChanged, TextBox17.TextChanged, TextBox16.TextChanged, TextBox15.TextChanged, TextBox21.TextChanged, TextBox24.TextChanged, TextBox23.TextChanged, TextBox22.TextChanged
        Judge_Volt_Range(sender, e)
    End Sub

    Private Sub TBox_Debounce_TextChanged(sender As Object, e As EventArgs) Handles TextBox3.TextChanged, TextBox6.TextChanged, TextBox4.TextChanged, TextBox8.TextChanged, TextBox14.TextChanged
        Judge_Debounce_Range(sender, e)
    End Sub

    Private Sub But_QueryLogInfo_Click(sender As Object, e As EventArgs) Handles But_QueryLogInfo.Click
        Dim send_data(20) As Byte

        send_data(0) = &HAE     '包头
        send_data(1) = 8     '长度
        send_data(2) = &H0     '校验
        send_data(3) = &H3     '命令 - 读取日志信息
        send_data(4) = &H0     '参数内容 - 

        send_data(5) = &H0
        send_data(6) = &H0

        send_data(7) = &HEA      '包尾

        send_data(2) = GetSumCheckMod(send_data, 8)

        SendPortData(send_data, 8)
    End Sub

    Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
        If CheckBox1.Checked = True Then
            CheckBox2.Checked = False
        Else
            CheckBox2.Checked = True
        End If
    End Sub

    Private Sub CheckBox2_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox2.CheckedChanged

        If CheckBox2.Checked = True Then
            CheckBox1.Checked = False
        Else
            CheckBox1.Checked = True
        End If

    End Sub

    ''' <summary>
    ''' 定期上报开关
    ''' </summary>
    Dim periodic_reporting_switch As Byte

    ''' <summary>
    ''' 开启定时上报
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click

        Dim send_data(20) As Byte

        If periodic_reporting_switch = &H1 Then
            periodic_reporting_switch = &H0

        Else
            periodic_reporting_switch = &H1

        End If

        send_data(0) = &HAE     '包头
        send_data(1) = 8     '长度
        send_data(2) = &H0     '校验
        send_data(3) = &H1     '命令 - 读取日志信息
        send_data(4) = &H4     '参数内容 - 

        send_data(5) = periodic_reporting_switch
        send_data(6) = &H0

        send_data(7) = &HEA      '包尾

        send_data(2) = GetSumCheckMod(send_data, 8)

        If SendPortData(send_data, 8) = True Then
            If periodic_reporting_switch = &H1 Then

                Button2.Text = "关闭上报"
                Button2.ForeColor = Color.Red
            Else

                Button2.Text = "开启上报"
                Button2.ForeColor = Color.Black
            End If
        End If


    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        Dim send_data(20) As Byte



        send_data(0) = &HAE     '包头
        send_data(1) = 8     '长度
        send_data(2) = &H0     '校验
        send_data(3) = &H2     '命令 - 读取日志信息
        send_data(4) = &H1     '参数内容 - 

        send_data(5) = &H0
        send_data(6) = &H0

        send_data(7) = &HEA      '包尾

        send_data(2) = GetSumCheckMod(send_data, 8)

        SendPortData(send_data, 8)

    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        '  4、读取校准信息
        Dim send_data(20) As Byte

        send_data(0) = &HAE     '包头
        send_data(1) = 8     '长度
        send_data(2) = &H0     '校验
        send_data(3) = &H2     '命令 - 读取日志信息
        send_data(4) = &H2     '参数内容 - 

        send_data(5) = &H0
        send_data(6) = &H0

        send_data(7) = &HEA      '包尾

        send_data(2) = GetSumCheckMod(send_data, 8)

        SendPortData(send_data, 8)
        '' 读取软件版本号 UUID
        'Dim send_data(20) As Byte

        'send_data(0) = &HAE     '包头
        'send_data(1) = 8     '长度
        'send_data(2) = &H0     '校验
        'send_data(3) = &H2     '命令 - 读取软件版本号
        'send_data(4) = &H3     '参数内容 - 

        'send_data(5) = &H0
        'send_data(6) = &H0

        'send_data(7) = &HEA      '包尾

        'send_data(2) = GetSumCheckMod(send_data, 8)

        'SendPortData(send_data, 8)


        '   5、读取实时状态信息
        'Dim send_data(20) As Byte

        'send_data(0) = &HAE     '包头
        'send_data(1) = 8     '长度
        'send_data(2) = &H0     '校验
        'send_data(3) = &H2     '命令 - 读取实时状态信息
        'send_data(4) = &H4     '参数内容 - 

        'send_data(5) = &H0
        'send_data(6) = &H0

        'send_data(7) = &HEA      '包尾

        'send_data(2) = GetSumCheckMod(send_data, 8)

        'SendPortData(send_data, 8)
    End Sub

    ''' <summary>
    ''' 调试信息输出开关
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub CheckBox3_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox3.CheckedChanged

        Dim send_data(20) As Byte
        send_data(0) = &HAE     '包头
        send_data(1) = 8     '长度
        send_data(2) = &H0     '校验
        send_data(3) = &H1     '命令 - 设置参数
        send_data(4) = &H6     '参数内容 - 设置调试信息状态

        If CheckBox3.Checked = True Then
            send_data(5) = &HFF     '开启调试信息
        Else

            send_data(5) = &H0      '关闭调试信息
        End If

        send_data(6) = &H0

        send_data(7) = &HEA      '包尾

        send_data(2) = GetSumCheckMod(send_data, 8)

        SendPortData(send_data, 8)



    End Sub

    Private Sub CheckBox4_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox4.CheckedChanged
        Dim send_data(20) As Byte
        send_data(0) = &HAE     '包头
        send_data(1) = 8     '长度
        send_data(2) = &H0     '校验
        send_data(3) = &H1     '命令 - 设置参数
        send_data(4) = &H5     '参数内容 - 设置调试信息状态

        If CheckBox4.Checked = True Then
            send_data(5) = &H1     '开启调试曲线信息
        Else
            send_data(5) = &H0      '关闭调试曲线信息
        End If

        send_data(6) = &H0

        send_data(7) = &HEA      '包尾

        send_data(2) = GetSumCheckMod(send_data, 8)

        SendPortData(send_data, 8)
    End Sub

    ''' <summary>
    ''' 复位命令下发
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub Button7_Click(sender As Object, e As EventArgs) Handles Button7.Click
        Dim send_data(20) As Byte
        send_data(0) = &HAE     '包头
        send_data(1) = 8     '长度
        send_data(2) = &H0     '校验
        send_data(3) = &H1     '命令 - 设置参数
        send_data(4) = &H7     '参数内容 - 复位


        send_data(5) = &H1      '关闭调试信息


        send_data(6) = &H0

        send_data(7) = &HEA      '包尾

        send_data(2) = GetSumCheckMod(send_data, 8)

        SendPortData(send_data, 8)
    End Sub


    ''' <summary>
    ''' 指定查询日志内容
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click

        Dim send_data(20) As Byte
        Dim temp_buff() As Byte = BitConverter.GetBytes(CInt(TextBox10.Text))

        send_data(0) = &HAE     '包头
        send_data(1) = 8     '长度
        send_data(2) = &H0     '校验
        send_data(3) = &H3     '命令 - 读取日志信息
        send_data(4) = &H1     '参数内容 - 

        send_data(5) = temp_buff(1)
        send_data(6) = temp_buff(0)

        send_data(7) = &HEA      '包尾

        send_data(2) = GetSumCheckMod(send_data, 8)

        SendPortData(send_data, 8)
    End Sub


    Dim g_Auto_Log_Query_Enable As Boolean = False
    Dim g_Auto_Log_Query_Cnt As Integer = 0
    Dim g_Auto_Log_Query_WriteCnt As Integer = 0
    Dim g_Auto_Log_Query_ReplyRev As Integer = 0


    ''' <summary>
    ''' 一键查询日志内容
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click

        If g_Auto_Log_Query_Enable Then
            '当前处于正在查询日志，停止查询
            Timer1.Interval = 10
            Timer1.Enabled = False
            g_Auto_Log_Query_Cnt = 0
            g_Auto_Log_Query_Enable = False

            Button6.ForeColor = Color.Black
            Button6.Text = "一键查询"

        Else
            '开启自动查询日志
            Timer1.Interval = 10
            Timer1.Enabled = True
            g_Auto_Log_Query_Cnt = 0
            g_Auto_Log_Query_Enable = True
            TextBox10.Text = 0

            Button6.ForeColor = Color.Red
            Button6.Text = "停止查询"
        End If


    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick


        g_Auto_Log_Query_Cnt += 1

        If g_Auto_Log_Query_Cnt >= 10 Then

            g_Auto_Log_Query_Cnt = 0
            'TextBox10.Text += 1

            Dim temp_num As Integer = CInt(TextBox10.Text)
            Dim temp_sum As Integer = CInt(TextBox9.Text)




            If SerialPort.IsOpen Then
                temp_num += 1
                TextBox10.Text = temp_num

                Button5.PerformClick()

                If temp_num >= temp_sum Then

                    '查询结束
                    Timer1.Interval = 10
                    Timer1.Enabled = False
                    g_Auto_Log_Query_Cnt = 0
                    g_Auto_Log_Query_Enable = False

                    Button6.ForeColor = Color.Black
                    Button6.Text = "一键查询"
                End If
            Else

                '当前处于正在查询日志，停止查询
                Timer1.Interval = 10
                Timer1.Enabled = False
                g_Auto_Log_Query_Cnt = 0
                g_Auto_Log_Query_Enable = False

                Button6.ForeColor = Color.Black
                Button6.Text = "一键查询"

                MsgBox("请打开串口！")
            End If






        End If



        'Console.WriteLine($"Timer1_Tick {g_Auto_Log_Query_Cnt}")



    End Sub

    ''' <summary>
    ''' 数据时间结构
    ''' </summary>
    Class LOG_DATE
        Public year As Int32
        Public month As Int32
        Public day As Int32
        Public hour As Int32
        Public minute As Int32
        Public second As Int32
        Public milliscond As Int32
    End Class

    Class LOG_Data_List
        Public original_data() As Byte
        Public sn As Byte
        Public time As DateTime
        Public type As Byte
        Public para_data() As Byte
        Public parsing As String
    End Class

    ''' <summary>
    ''' 解析表格排序
    ''' </summary>
    Enum form_grid1
        sn
        data_date
        data_parsing
    End Enum

    Dim Log_Data As New List(Of LOG_Data_List)

    Private Sub Grid_Format_initial()
        '新表格控件
        With Grid1

            .AutoRedraw = False    '禁止刷
            .Rows = 6           '返回或设置表格的行数
            .Cols = 4
            .DefaultFont = New Font("Tahoma", 8)       '设置字体
            .ExtendLastCol = True       '设置扩展最后一列的列宽，让表格可以充满控件
            .BackColor1 = Color.FromArgb(231, 235, 247)
            .GridColor = Color.FromArgb(148, 190, 231)


            .Cell(0, 1).Text = " 序号 "

            .Cell(0, 2).Text = "             时间            "

            .Cell(0, 3).Text = "内容"

            .Column(1).CellType = FlexCell.CellTypeEnum.TextBox
            .Column(2).CellType = FlexCell.CellTypeEnum.TextBox
            .Column(3).CellType = FlexCell.CellTypeEnum.TextBox

            .Column(1).AutoFit()
            .Column(2).AutoFit()
            .Column(3).AutoFit()

            .Column(1).Alignment = FlexCell.AlignmentEnum.CenterCenter
            .Column(2).Alignment = FlexCell.AlignmentEnum.CenterCenter          '居中对齐
            '.Column(3).Alignment = FlexCell.AlignmentEnum.LeftCenter            '左对齐
            .Column(3).Alignment = FlexCell.AlignmentEnum.CenterCenter            '居中对齐

            .SelectionMode = FlexCell.SelectionModeEnum.ByRow        '整行选取

            .DisplayRowNumber = True       '开启行号
            .AutoRedraw = True
            .Refresh()          '加载数据

        End With
    End Sub

    ''' <summary>
    ''' 将数据显示到表格中
    ''' </summary>
    ''' <param name="data_list"></param>
    Public Sub Grid_ADD_LOG_Data(data_list As List(Of LOG_Data_List), show_grid As FlexCell.Grid)
        Dim temp_num As Int32
        Dim temp_string As String
        '将数据对应的序号填充到对应的行号中

        If data_list.Count > show_grid.Rows - 1 Then
            'Console.WriteLine("Grid - 添加新行")
            show_grid.AddItem(" ", True)        '添加新行

        End If

        temp_num = data_list.Count - 1      '获取当前数据列表中有多少条数据
        temp_string = $"List Count:{temp_num} Rows:{show_grid.Rows}"
        'Console.WriteLine(temp_string)

        'show_grid.AddItem(" ", True)        '添加新行
        show_grid.Cell(data_list.Count, form_grid1.sn + 1).Text = data_list(temp_num).sn

        show_grid.Cell(data_list.Count, form_grid1.data_date + 1).Text = data_list(temp_num).time
        show_grid.Cell(data_list.Count, form_grid1.data_parsing + 1).Text = data_list(temp_num).parsing
    End Sub

    Public Sub Grid_Refresh_LOG_Data(data_list As List(Of LOG_Data_List), row As Integer, show_grid As FlexCell.Grid)
        Dim temp_num As Int32
        Dim temp_string As String
        '将数据对应的序号填充到对应的行号中

        If row > show_grid.Rows - 1 Then
            'Console.WriteLine("Grid - 添加新行")
            show_grid.AddItem(" ", True)        '添加新行

        End If

        temp_num = row - 1       '获取当前数据列表中有多少条数据
        temp_string = $"List Count:{temp_num} Rows:{show_grid.Rows}"
        'Console.WriteLine(temp_string)

        show_grid.Cell(row, form_grid1.sn + 1).Text = data_list(temp_num).sn
        show_grid.Cell(row, form_grid1.data_date + 1).Text = data_list(temp_num).time
        show_grid.Cell(row, form_grid1.data_parsing + 1).Text = data_list(temp_num).parsing
    End Sub
    Public TextBox2check As Boolean
    Private Sub ToolStripTextBox2_TextChanged(sender As Object, e As EventArgs) Handles ToolStripTextBox2.TextChanged
        TextBox2check = True
        If String.IsNullOrEmpty(ToolStripTextBox2.Text.Trim) Then
            TextBox2check = False
        End If
        Dim str As String
        For i = 0 To ToolStripTextBox2.Text.Length - 1
            str = ToolStripTextBox2.Text.Substring(i, 1)
            '判断 第i个字符 是否在 0到9 A到F 和空格
            If Not ((str >= "0" And str <= "9") OrElse
                    (str.ToUpper >= "A" And str.ToUpper <= "F") OrElse
                    (str.Equals(" "))) Then
                ToolStripTextBox2.ForeColor = Color.Red
                TextBox2check = False
                ''Console.WriteLine($"【{str}】:{ (str >= "0" And str <= "9") }")
                ''Console.WriteLine($"【{str}】:{ (str.ToUpper >= "A" And str.ToUpper <= "F") }")
                ''Console.WriteLine($"【{str}】:{ str.Equals(" ")}")

            Else
                ToolStripTextBox2.ForeColor = Color.Black
            End If
        Next
    End Sub
    Public CommandSetDic As Dictionary(Of String, Byte())

    Public Sub InitCommandSetDic()
        Dim str As String = ProcessTable.Cell(0, 0).Tag
        If String.IsNullOrEmpty(str) OrElse str.Length = 0 Then
            CommandSetDic = New Dictionary(Of String, Byte())
            CommandSetDic.Add("开启上报", HexStringToByteArray("AE 08 59 01 04 01 00 EA"))
            CommandSetDic.Add("关闭上报", HexStringToByteArray("AE 08 5A 01 04 00 00 EA"))
            CommandSetDic.Add("读取RTC时间", HexStringToByteArray("AE 08 5C 02 01 00 00 EA"))
            CommandSetDic.Add("设置RTC时间", {})
            CommandSetDic.Add("设置生产时间", {})
            CommandSetDic.Add("延时", {2})
            CommandSetDic.Add("获取服务器key", {0})
            CommandSetDic.Add("设置设备key", {0})
            CommandSetDic.Add("读取设备key", {"AE 08 54 02 09 00 00 EA"})
        Else
            CommandSetDic = JsonConvert.DeserializeObject(Of Dictionary(Of String, Byte()))(str)
        End If

        SendNodeDic = New List(Of (String, SendNode))

    End Sub
    Public FileCPatrh = $"{Application.StartupPath}\NT318"
    Public Sub SaveCommandSetDic()

        ProcessTable.Cell(0, 0).Tag = JsonConvert.SerializeObject(CommandSetDic)
        If Not IO.Directory.Exists(FileCPatrh & "\CommandSetDic") Then
            IO.Directory.CreateDirectory(FileCPatrh & "\CommandSetDic")
        End If
        ProcessTable.SaveFile(FileCPatrh & "\CommandSetDic.flx")
        '判断日文件夹在不在
        If Not IO.Directory.Exists(FileCPatrh & "\Log") Then
            IO.Directory.CreateDirectory(FileCPatrh & "\Log")
        End If
        Grid_table.SaveFile(FileCPatrh & $"\Log\{Now.ToString("yyyyMMddHHmmss")}.flx")
    End Sub
    Public Sub InitLoadProcessTable(Optional isFile As Boolean = True)
        If isFile Then
            If IO.File.Exists(FileCPatrh & "\CommandSetDic.flx") Then
                ProcessTable.OpenFile(FileCPatrh & "\CommandSetDic.flx")
                Return
            End If
        End If

        ProcessTable.NewFile()
        ProcessTable.Cols = 5
        ProcessTable.Rows = 1
        ProcessTable.DisplayRowNumber = True
        ProcessTable.ExtendLastCol = True

        ProcessTable.Cell(0, 0).Text = "序号"
        ProcessTable.Cell(0, 1).Text = "勾选"
        ProcessTable.Cell(0, 2).Text = "命令别名"
        ProcessTable.Cell(0, 3).Text = "命令"
        ProcessTable.Cell(0, 4).Text = "发送状态"

        ProcessTable.Column(0).Width = 50
        ProcessTable.Column(1).Width = 20
        ProcessTable.Column(2).Width = 120
        ProcessTable.Column(3).Width = 200
        ProcessTable.Column(4).Width = 100

        ProcessTable.Column(0).Alignment = AlignmentEnum.GeneralCenter
        ProcessTable.Column(1).Alignment = AlignmentEnum.GeneralCenter
        ProcessTable.Column(2).Alignment = AlignmentEnum.GeneralCenter
        ProcessTable.Column(3).Alignment = AlignmentEnum.GeneralCenter
        ProcessTable.Column(4).Alignment = AlignmentEnum.GeneralCenter

        ProcessTable.Column(1).CellType = CellTypeEnum.CheckBox
        ProcessTable.Column(2).CellType = CellTypeEnum.ComboBox
        ProcessTable.Column(3).Locked = True

    End Sub
    Public Sub InitGrid_table()
        With Grid_table
            .NewFile()
            .Rows = 1
            .Cols = TableEnum.MAX
            .DisplayRowNumber = True
            .ExtendLastCol = True
            For i = 0 To TableEnum.MAX - 1
                If i = 0 Then
                    .Column(0).Width = 50
                End If
                .Cell(0, i).Text = GetTableEnumName(i)
                .Column(i).Alignment = AlignmentEnum.GeneralCenter
                .Column(i).Locked = True
            Next
        End With
    End Sub

    Private Sub ToolStripButton1_Click(sender As Object, e As EventArgs) Handles ToolStripButton1.Click

        If String.IsNullOrEmpty(T_CommandAlias.Text.Trim) Then
            MsgBox("请输入命令别名")
            Return
        End If
        If String.IsNullOrEmpty(ToolStripTextBox2.Text.Trim) Then
            MsgBox("请输入命令")
            Return
        End If
        Dim CommandAlia As String = T_CommandAlias.Text.Trim
        Dim Command As String = ToolStripTextBox2.Text.Trim


        If CommandSetDic.ContainsKey(CommandAlia) Then
            '提示框提示用户是否需要覆盖
            If MsgBox("该命令别名已存在，是否覆盖？", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
                CommandSetDic(CommandAlia) = HexStringToByteArray(Command)
            End If
        Else
            CommandSetDic.Add(CommandAlia, HexStringToByteArray(Command))
        End If

    End Sub

    ''' <summary>
    ''' 将字符串按 UTF-8 编码转成 Byte 数组。
    ''' </summary>
    Public Function StringToBytes(ByVal s As String) As Byte()

        Return System.Text.Encoding.UTF8.GetBytes(s)
    End Function
    '将16进制字符串转换为字节数组
    Private Function HexStringToByteArray(hex As String) As Byte()

        Dim bytes As New List(Of Byte)
        hex = hex.Replace(" ", "").Trim.ToUpper()
        For i As Integer = 0 To hex.Length - 1 Step 2
            Dim hexByte As String = hex.Substring(i, 2)
            bytes.Add(Convert.ToByte(hexByte, 16))
        Next
        Return bytes.ToArray()
    End Function

    '将字节数组转换为16进制字符串
    Private Function ByteArrayToHexString(bytes As Byte()) As String
        If bytes Is Nothing OrElse bytes.Length = 0 Then Return ""
        Dim hex As String = ""
        For Each b As Byte In bytes
            hex += b.ToString("X2") & " "
        Next
        Return hex.Trim()

    End Function

    Private Sub ProcessTable_ComboDropDown(Sender As Object, e As Grid.ComboDropDownEventArgs) Handles ProcessTable.ComboDropDown
        If e.Row = 0 Then Return
        If e.Col = 2 Then
            ProcessTable.ComboBox(e.Col).Items.Clear()
            ProcessTable.ComboBox(e.Col).Items.AddRange(CommandSetDic.Keys.ToArray())
        End If
    End Sub

    Public SendNodeDic As List(Of (String, SendNode))
    Public StartSendThread As Thread
    Public IsRuningTest As Boolean = False
    Public IsStopTest As Boolean = False
    Private Sub ToolStripButton3_Click(sender As Object, e As EventArgs) Handles ToolStripButton3.Click
        If ToolStripButton3.Text = "开始校时" Then
            If Not SerialPort.IsOpen Then
                MsgBox("串口未打开")
                Return
            End If


            ToolStripButton3.Text = "停止校时"
            ToolStripButton3.ForeColor = Color.Red
            IsRuningTest = True
            IsStopTest = False
            isnotSendNode = True
            IsSetTime = False
            IsRtcTime = False
            SendNodeDic.Clear()
            Label38.ForeColor = Color.Yellow
            If ProcessTable.Rows = 1 Then
                ' MsgBox("命令列表为空！！！")
                Label38.Text = "命令列表为空！！！"
                Label38.ForeColor = Color.Red
                Return
            End If
            For i = 1 To ProcessTable.Rows - 1
                If ProcessTable.Cell(i, 1).Text = "1" Then
                    ' ProcessTable.Rows = ProcessTable.Rows - 1
                    SendNodeDic.Add((ProcessTable.Cell(i, 2).Text, New SendNode()))
                End If
            Next

            Button24.PerformClick()

            '运行线程如果 线程不存在则新建线程并运行如果线程存在中则先终止再新启动
            If StartSendThread Is Nothing OrElse StartSendThread.ThreadState = ThreadState.Stopped Then
                StartSendThread = New Thread(AddressOf StartSendThreadRuning)
                StartSendThread.Start()
            Else
                StartSendThread.Abort()
                StartSendThread = New Thread(AddressOf StartSendThreadRuning)
                StartSendThread.Start()
            End If


        Else
            ToolStripButton3.Text = "开始校时"
            ToolStripButton3.ForeColor = Color.Black
            IsRuningTest = False
            IsStopTest = True
        End If


    End Sub

    Delegate Sub delegateRefreshCaptureText(Textcolor As Color， Textstr As String)


    Public Sub RefreshCaptureText(Textcolor As Color， Textstr As String)
        If Me.InvokeRequired = True Then
            Dim dd As New delegateRefreshCaptureText(AddressOf RefreshCaptureText)
            Me.Invoke(dd, {Textcolor, Textstr})
        Else
            If Textcolor = Color.Red Then
                Label38.Text = "失败"
                Label38.ForeColor = Textcolor
            Else

                If Textcolor = Color.Green Then
                    If Textstr.Contains("校时完成") Then
                        Label38.Text = "成功"
                        Label38.ForeColor = Textcolor
                    Else
                        Label38.Text = "校时中"
                        Label38.ForeColor = Color.Yellow
                    End If
                End If
            End If
            'Label38.Text = Textstr

        End If
    End Sub
    Public Sub RefreshCaptureRichText(Textcolor As Color， Textstr As String)
        If Me.InvokeRequired = True Then
            Dim dd As New delegateRefreshCaptureText(AddressOf RefreshCaptureRichText)
            Me.Invoke(dd, {Textcolor, Textstr})
        Else
            RichTextBox1.Text = Textstr
            Label38.ForeColor = Textcolor
        End If




    End Sub


    Public Sub StartSendThreadRuning()
        ' SendPortData1()

        Dim result As String = String.Empty
        Dim nextnode As SendNode
        For Each node In SendNodeDic
            Console.WriteLine(node.Item1)
            If node.Item1.Equals("读取RTC时间") Then
                Console.WriteLine(node.Item1)
            End If
            If IsRuningTest = False Then Exit For

            If isnotSendNode = False Then
                RefreshCaptureText(Color.Red, "校时失败!!")
                IsRuningTest = False
                Exit For
            End If

            '循环等待节点接收状态改变
            While node.Item2.RecvStatus = SendNode.RecvStatusEnum.None
                If IsRuningTest = False Then Exit For
                If node.Item1.Equals("延时") Then
                    node.Item2.AddRecvData(CommandSetDic.Item("延时"))
                    node.Item2.ResendRefresh()
                    Thread.Sleep(CInt(CommandSetDic.Item("延时")(0)) * 1000)
                    node.Item2.RecvRefresh(CommandSetDic.Item("延时"))
                    Exit While
                End If

                If node.Item1.Equals("获取服务器key") Then
                    node.Item2.AddRecvData({0})
                    node.Item2.ResendRefresh()
                    AppendTipText($"Com-TX:( {Now:HH:mm:ss:fff}):获取服务器key" & vbCrLf, Color.Green)

                    '从 后往前 遍历 SendNodeDic 列表
                    Dim ifnode As (String, SendNode)
                    For i As Integer = SendNodeDic.Count - 1 To 0 Step -1
                        ifnode = SendNodeDic(i)
                        If ifnode.Item1.Equals("读取软件版本号") AndAlso ifnode.Item2.RecvStatus = SendNode.RecvStatusEnum.Recv Then
                            Exit For
                        End If
                    Next

                    If Not IsNothing(ifnode) AndAlso ifnode.Item1.Equals("读取软件版本号") AndAlso ifnode.Item2.RecvStatus = SendNode.RecvStatusEnum.Recv Then


                        Dim MachineType As Integer
                        Dim Brandld As Integer
                        Dim buff As Byte() = ifnode.Item2.RecvDataLisr(0)


                        MachineType = CombineTwoBytesToDecimal(buff(7), buff(8))
                        Brandld = CombineTwoBytesToDecimal(buff(9), buff(10))

                        Dim uuid As String = ""
                        For ni As Integer = 1 To buff(13)
                            uuid += $"{Hex2(buff(13 + ni))} "
                        Next
                        uuid = uuid.Replace(" ", "")
                        Dim apinode As Program = API_AllocationBarCode(uuid, MachineType, Brandld)
                        If IsNothing(apinode) Then

                        Else
                            AppendTipText($"Com-TX:( {Now:HH:mm:ss:fff}):获取服务器ClientId：{apinode.Response.ClientId}key:{apinode.Response.SecretKey}" & vbCrLf, Color.Blue)
                            node.Item2.RecvDatadic = apinode
                            node.Item2.RecvRefresh({0})
                        End If

                    Else
                        IsRuningTest = False '退出流程
                        RefreshCaptureText(Color.Red, $"节点:{node.Item1} :执行失败！")
                        Exit While
                    End If

                End If
                If node.Item1.Equals("设置设备key") Then
                    Dim ifnode As (String, SendNode)
                    Dim Nfnode As (String, SendNode)
                    For i As Integer = SendNodeDic.Count - 1 To 0 Step -1
                        If IsNothing(ifnode) Then
                            ifnode = SendNodeDic(i)
                            If ifnode.Item1.Equals("获取服务器key") AndAlso ifnode.Item2.RecvStatus = SendNode.RecvStatusEnum.Recv Then
                            Else
                                ifnode = Nothing
                            End If
                        End If
                        If IsNothing(Nfnode) Then
                            Nfnode = SendNodeDic(i)
                            If Nfnode.Item1.Equals("读取设备key") AndAlso Nfnode.Item2.RecvStatus = SendNode.RecvStatusEnum.Recv Then
                            Else
                                Nfnode = Nothing
                            End If
                        End If
                    Next
                    If Not IsNothing(ifnode.Item2) AndAlso Not IsNothing(Nfnode.Item2) Then
                        Dim devkey As Integer
                        Dim devClientId As String
                        Dim buff = Nfnode.Item2.RecvDataLisr(0)
                        Dim src As Byte() = Slice(buff, 5, 4)
                        devkey = BytesLE4ToInt(src)
                        src = Slice(buff, 9, buff(1) - 10)
                        devClientId = BytesToString(src).Trim

                        Dim apinode As Program = ifnode.Item2.RecvDatadic

                        If apinode.Response.SecretKey.Equals(devkey.ToString) AndAlso apinode.Response.ClientId.Equals(devClientId) Then
                            AppendTipText($"Com-TX:( {Now:HH:mm:ss:fff}):获取服务器ClientId：{apinode.Response.ClientId}key:{apinode.Response.SecretKey}" & vbCrLf, Color.Blue)
                            node.Item2.RecvRefresh({0})
                            Exit While
                        End If

                    End If

                End If


                '判断发送状态是否改变0：未发送，1：发送成功，2：发送失败
                If node.Item2.SendStatus = SendNode.SendStatusEnum.None Then
                    '发送数据并更新发送状态
                    result = SendPortData1(node.Item1, node.Item2)
                    AppendTipText($"Com-TX:【{node.Item1}】", Color.Green)
                    AppendTipText("(" & Now.ToString("yyyy-MM-dd HH:mm:ss") & "):", Color.Black)
                    AppendTipText(ByteToString(node.Item2.SendData) & vbCrLf, Color.Green)
                    If String.IsNullOrEmpty(result) Then
                        result = $"节点:{node.Item1} :发送成功！"
                        RefreshCaptureText(Color.Green, result)
                    Else
                        IsRuningTest = False '退出流程
                        RefreshCaptureText(Color.Red, result)
                    End If
                Else
                    '判断节点是否需要重新发送
                    If node.Item2.NeedResend() Then
                        result = SendPortData1(node.Item1, node.Item2)
                        AppendTipText("Com-TX:", Color.Green)
                        AppendTipText("(" & Now.ToString("yyyy-MM-dd HH:mm:ss") & "):", Color.Black)
                        AppendTipText(ByteToString(node.Item2.SendData) & vbCrLf, Color.Green)
                        If String.IsNullOrEmpty(result) Then
                            result = $"节点:{node.Item1} :重发[{ node.Item2.SendCount}] 送成功！"
                            RefreshCaptureText(Color.Green, result)
                        Else
                            IsRuningTest = False '退出流程
                            RefreshCaptureText(Color.Red, result)
                        End If
                    Else
                        If node.Item2.SendCount < 3 Then
                        Else
                            IsRuningTest = False '退出流程
                            RefreshCaptureText(Color.Red, $"节点:{node.Item1} :发送失败！")
                        End If
                    End If

                End If



                '延时(100)
                Thread.Sleep(100)

            End While


        Next

        '数据入库
        Dim sresult As String = StoreTestDataInTheDatabase()
        If String.IsNullOrEmpty(sresult) Then
            If IsRuningTest = True Then
                RefreshCaptureText(Color.Green, "校时完成！")
            End If
        Else
            RefreshCaptureText(Color.Red, sresult)
        End If


        delToolStripButton3()

    End Sub

    Public Shared Function API_AllocationBarCode(Mcu_Uuid As String, MachineType As Integer, Brandld As Integer) As Program

        Dim jsonString As String = String.Empty
        Dim dic As New Dictionary(Of String， String）
        dic.Add("Mcu_Uuid", Mcu_Uuid)
        dic.Add("MachineType", MachineType)
        dic.Add("Brandld", Brandld)
        Dim jsonstr As String = JsonConvert.SerializeObject(dic)
        Try
            jsonString = PostData2("http://iot.uts-data.com:8086/api/Deviceinfoes/GetOrUpdateDevice", $"{jsonstr}")
        Catch ex As Exception
            MsgBox($"网络API调用错误，请联系管理员。")
            Return Nothing
        End Try
        ''Console.WriteLine(jsonString)

        If jsonString = Nothing Then
            Return Nothing
        End If

        Dim login As Program
        Try
            login = JsonConvert.DeserializeObject(Of Program)(jsonString)
            If Not IsNothing(login) AndAlso Not IsNothing(login.IsOk) Then
                If login.IsOk Then
                    Return login
                Else
                    Return Nothing
                End If
                Return Nothing
            Else
                Return Nothing
            End If
        Catch ex As Exception
            MsgBox($"Json数据转换错误，请联系管理员。详情 ：Json data to AllocationAPI  error")
            Return Nothing
        End Try

    End Function
    Public Shared Function PostData2(ByVal url As String, ByVal data As String) As String
        ServicePointManager.Expect100Continue = False
        Dim request As HttpWebRequest = WebRequest.Create(url)
        '//Post请求方式
        request.Method = "POST"

        '内容类型
        request.ContentType = "application/json"
        '将URL编码后的字符串转化为字节
        Dim encoding As New UTF8Encoding()
        Dim bys As Byte() = encoding.GetBytes(data)
        '设置请求的 ContentLength 
        request.ContentLength = bys.Length
        '获得请 求流
        Dim newStream As Stream = request.GetRequestStream()
        newStream.Write(bys, 0, bys.Length)
        newStream.Close()
        '获得响应流
        Dim sr As StreamReader = New StreamReader(request.GetResponse().GetResponseStream)
        Return sr.ReadToEnd
    End Function
    Public Shared Function PostData(ByVal url As String, ByVal data As String) As String

        ServicePointManager.Expect100Continue = False
        Dim request As HttpWebRequest = CType(WebRequest.Create(url), HttpWebRequest)
        '//Post请求方式
        request.Method = "POST"

        '内容类型
        request.ContentType = "application/x-www-form-urlencoded"
        '将URL编码后的字符串转化为字节
        Dim encoding As New UTF8Encoding()

        Dim bys As Byte() = encoding.GetBytes(data)
        '设置请求的 ContentLength 
        request.ContentLength = bys.Length
        '获得请 求流
        Dim newStream As Stream = request.GetRequestStream()
        newStream.Write(bys, 0, bys.Length)
        newStream.Close()
        '获得响应流
        Dim sr As StreamReader = New StreamReader(request.GetResponse().GetResponseStream)
        Return sr.ReadToEnd
    End Function
    Delegate Sub delegateToolStripButton3()
    Public Sub delToolStripButton3()
        If Me.InvokeRequired = True Then
            Dim dd As New delegateToolStripButton3(AddressOf delToolStripButton3)
            Me.Invoke(dd)
        Else
            ToolStripButton3.Text = "开始校时"
            ToolStripButton3.ForeColor = Color.Black
            IsRuningTest = False
            IsStopTest = True
        End If
    End Sub

    'byte 转16进制字符串
    Public Function Hex2(ByVal b As Byte) As String
        Return b.ToString("X2")
    End Function
    '测试数据入库
    Public Function StoreTestDataInTheDatabase() As String
        '判断测试是主动停止还是被动停止
        Dim result As String = String.Empty
        If IsStopTest = True Then
            result = "测试被停止！"
            Return result
        End If
        Dim dic As New Dictionary(Of String, String)
        Dim buff() As Byte
        dic.Add("测试时间", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
        dic.Add("测试结果", "1")
        dic.Add("测试信息", "成功")

        If IsSetTime = True Then
            dic.Item("测试结果") = "0"
            dic.Item("测试信息") = $"失败：设置生产时间失败！"
            result = $"失败：设置生产时间失败！"
            RefreshCaptureText(Color.Red, "失败：设置生产时间失败！")
        End If
        If IsRtcTime = True Then
            dic.Item("测试结果") = "0"
            dic.Item("测试信息") = $"失败：设备RTC时钟故障"
            result = $"失败：设备RTC时钟故障"
            RefreshCaptureText(Color.Red, "失败：设备RTC时钟故障")
        End If
        Dim node As (String, SendNode)
        For i = 0 To SendNodeDic.Count - 1
            node = SendNodeDic(i)
            If node.Item1.Equals("延时") Then
                Continue For
            End If
            If node.Item1.Equals("获取服务器key") Then
                '[服务器key] Text，
                '                        '                           [服务器ClientId] TEXT，
                Dim apinode As Program = node.Item2.RecvDatadic
                dic.Add("服务器key", apinode.Response.SecretKey)
                dic.Add("服务器ClientId", apinode.Response.ClientId)
                Continue For
            End If
            If node.Item2.SendStatus = SendNode.SendStatusEnum.Send Then
                If &H2 = node.Item2.SendData(3) Then
                    '判断接收状态是否为成功
                    If node.Item2.RecvStatus = SendNode.RecvStatusEnum.Recv Then
                        buff = node.Item2.RecvDataLisr(0)
                        If node.Item2.SendData(3) = buff(3) AndAlso node.Item2.SendData(4) = buff(4) Then
                            Try
                                Select Case buff(4)
                                    Case 1 '读取RTC时间
                                        'AppendTipText($"RTC: 20{Hex(buff(6))}-{Hex(buff(7))}-{Hex(buff(8))} {Hex(buff(9))}:{Hex(buff(10))}:{Hex(buff(11))} {Hex(buff(12))} " & vbCrLf, Color.Blue)
                                        dic.Add("RTC时间", $"20{Hex2(buff(6))}-{Hex2(buff(7))}-{Hex2(buff(8))} {Hex2(buff(9))}:{Hex2(buff(10))}:{Hex2(buff(11))}")
                                        dic.Add("RTC星期", $"{Hex(buff(12))}")
                                    Case 2 '读取设置参数信息

                                        '00 - 读取校准结果：0x00:校准成功， 其他值： 校准失败
                                        '		1E 00 		稳定消抖时间 - 单位：s
                                        '2C 01 		背景值滤波长度 - 单位：s
                                        '                            FA 0F 		传感器极大值
                                        '        0A 00 		传感器极小值
                                        '		03 00 		预热时间 - 单位：分钟
                                        '34 08 		LEV 10% 对应的ADC 值
                                        '		20 03 		LEV 0%  对应的ADC 值
                                        '		96 00 		触发 - 消抖次数
                                        '		96 00 		释放 - 消抖次数
                                        '		64 00 		稳定阈值
                                        '		32 00 		报警点提前量
                                        '		B0 4 		校准超时 - 单位： S
                                        '14 00 		LEV 0% 校准最小值
                                        '		AC 0D 		LEV 0% 校准最大值
                                        '        F4 1 		LEV 10% 校准最小值
                                        '        FA 0F 		LEV 10% 校准最大值
                                        '        14 00 		差值 校准最小值
                                        '		FA 0F 		差值 校准最大值
                                        '        C8 0 		泄露恢复正常 判定条件1： 处于基准的XX倍数以内
                                        '05 00 		泄露恢复正常 判定条件1：处于基准的XX倍数以内的消抖时间 单位： 秒
                                        '84 03 		泄露恢复正常 判定条件2：处于基准的XX倍数以内
                                        '78 00 		泄露恢复正常 判定条件2：处于基准的XX倍数以内的消抖时间 单位： 分钟
                                        'DC 63 E6 67 设备生产时间
                                        If dic.ContainsKey("校准结果") Then
                                            Select Case buff(5)
                                                Case 0
                                                    dic("校准结果") = $"{(buff(5))}_OK"
                                                Case 1
                                                    dic("校准结果") = $"{(buff(5))}_未校准"
                                                Case 2
                                                    dic("校准结果") = $"{(buff(5))}_校验错误"
                                            End Select

                                            dic("温度校准算法选择") = CombineTwoBytesToDecimal(buff(6), buff(7))
                                            dic("回差") = CombineTwoBytesToDecimal(buff(8), buff(9))
                                            dic("传感器极大值") = CombineTwoBytesToDecimal(buff(10), buff(11))
                                            dic("传感器极小值") = CombineTwoBytesToDecimal(buff(12), buff(13))
                                            dic("预热时间_分") = CombineTwoBytesToDecimal(buff(14), buff(15))
                                            dic("ADC_LEV_10") = CombineTwoBytesToDecimal(buff(16), buff(17))
                                            dic("ADC_LEV_0") = CombineTwoBytesToDecimal(buff(18), buff(19))
                                            dic("触发_消抖次数") = CombineTwoBytesToDecimal(buff(20), buff(21))
                                            dic("释放_消抖次数") = CombineTwoBytesToDecimal(buff(22), buff(23))
                                            dic("稳定阈值") = CombineTwoBytesToDecimal(buff(24), buff(25))
                                            dic("报警点提前量") = CombineTwoBytesToDecimal(buff(26), buff(27))
                                            dic("校准超时_秒") = CombineTwoBytesToDecimal(buff(28), buff(29))
                                            dic("IHIOT_心跳包上报间隔") = CombineTwoBytesToDecimal(buff(30), buff(31))
                                            dic("OSD显示模式") = CombineTwoBytesToDecimal(buff(32), buff(33))
                                            dic("检测故障最小值") = CombineTwoBytesToDecimal(buff(34), buff(35))
                                            dic("检测故障最大值") = CombineTwoBytesToDecimal(buff(36), buff(37))
                                            dic("校准最小值_LEV_0") = CombineTwoBytesToDecimal(buff(38), buff(39))
                                            dic("校准最大值_LEV_0") = CombineTwoBytesToDecimal(buff(40), buff(41))
                                            dic("校准最小值_LEV_10") = CombineTwoBytesToDecimal(buff(42), buff(43))
                                            dic("校准最大值_LEV_10") = CombineTwoBytesToDecimal(buff(44), buff(45))
                                            dic("校准最小值_差值") = CombineTwoBytesToDecimal(buff(46), buff(47))
                                            dic("校准最大值_差值") = CombineTwoBytesToDecimal(buff(48), buff(49))
                                            dic("自定义LEV_10_对应的ADC") = CombineTwoBytesToDecimal(buff(50), buff(51))
                                            dic("自定义LEV_0_对应的ADC") = CombineTwoBytesToDecimal(buff(52), buff(53))
                                            dic("泄露恢复正常_条件2") = CombineTwoBytesToDecimal(buff(54), buff(55))
                                            dic("泄露恢复正常_条件2消抖时间_分") = CombineTwoBytesToDecimal(buff(56), buff(57))
                                            dic("设备生产时间") = CombineFourBytesToLong(buff(61), buff(60), buff(59), buff(58))

                                        Else
                                            dic.Add("校准结果", $"{(buff(5))}")
                                            dic("温度校准算法选择") = CombineTwoBytesToDecimal(buff(6), buff(7))
                                            dic("回差") = CombineTwoBytesToDecimal(buff(8), buff(9))
                                            dic("传感器极大值") = CombineTwoBytesToDecimal(buff(10), buff(11))
                                            dic("传感器极小值") = CombineTwoBytesToDecimal(buff(12), buff(13))
                                            dic("预热时间_分") = CombineTwoBytesToDecimal(buff(14), buff(15))
                                            dic("ADC_LEV_10") = CombineTwoBytesToDecimal(buff(16), buff(17))
                                            dic("ADC_LEV_0") = CombineTwoBytesToDecimal(buff(18), buff(19))
                                            dic("触发_消抖次数") = CombineTwoBytesToDecimal(buff(20), buff(21))
                                            dic("释放_消抖次数") = CombineTwoBytesToDecimal(buff(22), buff(23))
                                            dic("稳定阈值") = CombineTwoBytesToDecimal(buff(24), buff(25))
                                            dic("报警点提前量") = CombineTwoBytesToDecimal(buff(26), buff(27))
                                            dic("校准超时_秒") = CombineTwoBytesToDecimal(buff(28), buff(29))
                                            dic("IHIOT_心跳包上报间隔") = CombineTwoBytesToDecimal(buff(30), buff(31))
                                            dic("OSD显示模式") = CombineTwoBytesToDecimal(buff(32), buff(33))
                                            dic("检测故障最小值") = CombineTwoBytesToDecimal(buff(34), buff(35))
                                            dic("检测故障最大值") = CombineTwoBytesToDecimal(buff(36), buff(37))
                                            dic("校准最小值_LEV_0") = CombineTwoBytesToDecimal(buff(38), buff(39))
                                            dic("校准最大值_LEV_0") = CombineTwoBytesToDecimal(buff(40), buff(41))
                                            dic("校准最小值_LEV_10") = CombineTwoBytesToDecimal(buff(42), buff(43))
                                            dic("校准最大值_LEV_10") = CombineTwoBytesToDecimal(buff(44), buff(45))
                                            dic("校准最小值_差值") = CombineTwoBytesToDecimal(buff(46), buff(47))
                                            dic("校准最大值_差值") = CombineTwoBytesToDecimal(buff(48), buff(49))
                                            dic("自定义LEV_10_对应的ADC") = CombineTwoBytesToDecimal(buff(50), buff(51))
                                            dic("自定义LEV_0_对应的ADC") = CombineTwoBytesToDecimal(buff(52), buff(53))
                                            dic("泄露恢复正常_条件2") = CombineTwoBytesToDecimal(buff(54), buff(55))
                                            dic("泄露恢复正常_条件2消抖时间_分") = CombineTwoBytesToDecimal(buff(56), buff(57))
                                            dic("设备生产时间") = CombineFourBytesToLong(buff(61), buff(60), buff(59), buff(58))
                                        End If


                                    Case 3 '读取软件版本号
                                        '04 	软件版本号
                                        '03     硬件板本号
                                        '		78 00 3E 00 0F 80 13 11 0C 80 		UUID

                                        dic.Add("软件版本号", $"{Hex(buff(5))}")
                                        dic.Add("硬件版本号", $"{Hex(buff(6))}")
                                        dic.Add("设备类型ID", CombineTwoBytesToDecimal(buff(7), buff(8)))
                                        dic.Add("厂牌ID", CombineTwoBytesToDecimal(buff(9), buff(10)))
                                        dic.Add("机型ID", CombineTwoBytesToDecimal(buff(11), buff(12)))
                                        Dim uuid As String = ""
                                        For ni As Integer = 1 To buff(13)
                                            uuid += $"{Hex2(buff(13 + ni))} "
                                        Next
                                        dic.Add("UUID", $"{uuid}")
                                    Case 4 '读取实时状态
                                        '       02 00 		状态机 - 正常监控 类型int16_t
                                        '		C6 1 		实时值 - 类型int16_t
                                        '       C9 1 		背景值 - 类型int16_t
                                        '       C6 1 		基底值 - 类型int16_t
                                        '       FD FF 		差值   - 类型int16_t
                                        '       00 00 		LEL百分比 - 类型int16_t
                                        '		01 00 		稳定状态 - 类型int16_t
                                        '		0E A2 		基底值差值百分比1 - 类型int16_t
                                        '		3B A4 		基底值+差值百分比2 - 类型int16_t
                                        '		4C 00 		温度 - 类型int16_t
                                        dic.Add("状态机", ReadTheStatus(CombineTwoBytesToDecimal(buff(5), buff(6))))
                                        dic.Add("实时值", CombineTwoBytesToDecimal(buff(7), buff(8)))
                                        dic.Add("背景值", CombineTwoBytesToDecimal(buff(9), buff(10)))
                                        dic.Add("基底值", CombineTwoBytesToDecimal(buff(11), buff(12)))
                                        dic.Add("差值", CombineTwoBytesToDecimaShort(buff(13), buff(14)))
                                        dic.Add("LEL百分比", CombineTwoBytesToDecimal(buff(15), buff(16)))
                                        dic.Add("稳定状态", CombineTwoBytesToDecimal(buff(17), buff(18)))
                                        dic.Add("基底值差值百分比1", CombineTwoBytesToDecimal(buff(20), buff(19)))
                                        dic.Add("基底值差值百分比2", CombineTwoBytesToDecimal(buff(22), buff(21)))
                                        dic.Add("温度", CombineTwoBytesToDecimal(buff(23), buff(24)))
                                    Case 9 '读设备 key

                                        '[服务器key] Text，
                                        '                           [服务器ClientId] TEXT，
                                        Dim src As Byte() = Slice(buff, 5, 4)
                                        If dic.ContainsKey("设备ClientId") Then
                                            dic.Item("设备ClientId") = BytesLE4ToInt(src)
                                        Else
                                            dic.Add("设备ClientId", BytesLE4ToInt(src))
                                        End If

                                        src = Slice(buff, 9, buff(1) - 10)
                                        If dic.ContainsKey("设备key") Then
                                            dic.Item("设备key") = BytesToString(src)
                                        Else
                                            dic.Add("设备key", BytesToString(src))
                                        End If

                                    Case Else
                                        dic.Item("测试结果") = "0"
                                        dic.Item("测试信息") = $"节点:{node.Item1} :接收数据未找到对应解析方式！"
                                        result = $"节点:{node.Item1} :接收数据未找到对应解析方式！"
                                        Exit For
                                End Select

                            Catch ex As Exception
                                dic.Item("测试结果") = "0"
                                dic.Item("测试信息") = $"节点:{node.Item1} :接收数据异常！"
                                result = $"节点:{node.Item1} :接收数据异常！"
                                Exit For
                            End Try

                        Else
                            dic.Item("测试结果") = "0"
                            dic.Item("测试信息") = $"节点:{node.Item1} :接收数据异常！"
                            result = $"节点:{node.Item1} :接收数据异常！"
                            Exit For
                        End If


                    Else
                        '接收失败
                        dic.Item("测试结果") = "0"
                        dic.Item("测试信息") = $"节点:{node.Item1} :接收失败！"
                        result = $"节点:{node.Item1} :接收失败！"
                        Exit For
                    End If
                End If
            Else
                If node.Item2.SendStatus = SendNode.SendStatusEnum.None Then
                    dic.Item("测试结果") = "0"
                    dic.Item("测试信息") = $"失败 :设备无校准参数信息！"
                    result = $"失败 :设备无校准参数信息！"
                ElseIf node.Item2.SendStatus = SendNode.SendStatusEnum.Timeout Then
                    dic.Item("测试结果") = "0"
                    dic.Item("测试信息") = $"节点:{node.Item1} :发送失败！"
                    result = $"节点:{node.Item1} :发送失败！"

                End If
                Exit For
            End If

        Next
        Dim nstr As String = JsonConvert.SerializeObject(dic)
        '入库
        WriteToTable(dic)

        Dim localConn As New DbConnectionStringBuilder
        localConn.Add("Data Source", Sqlitedbpath)
        Using db As New DbExecutor(DbExecutor.DbTypeEnum.Sqlite, localConn.ToString())
            Try
                db.Open()
                Dim caint = db.ExecuteNonQuery(db.CmdHelper.Insert(SqliteTableName, dic))
                If caint = 0 Then
                    result = "Sqlite入库失败！"
                End If
                db.Close()
            Catch ex As Exception
                result = $"Sqlite入库失败！{ex.Message}"
            End Try
            db.Close()
            ' Return True
        End Using


        Using db As New DbExecutor(DbExecutor.DbTypeEnum.Mysql, DbConnString)
            Try
                db.Open()
                Dim caint = db.ExecuteNonQuery(db.CmdHelper.Insert(SqliteTableName, dic))
                If caint = 0 Then
                    result = "Mysql入库失败！"
                End If
                db.Close()
            Catch ex As Exception
                result = $"Mysql入库失败！{ex.Message}"
            End Try
            db.Close()
            ' Return True
        End Using
        Return result

    End Function
    ''' <summary>
    ''' 将 Byte 数组按 UTF-8 编码转成字符串。
    ''' </summary>
    Public Function BytesToString(buf As Byte()) As String
        If buf Is Nothing Then Return ""
        Return System.Text.Encoding.UTF8.GetString(buf)
    End Function

    ''' <summary>
    ''' 从原数组截取部分数据为新数组。
    ''' </summary>
    ''' <param name="source">源数组</param>
    ''' <param name="start">起始索引（0 起算）</param>
    ''' <param name="length">要截取的长度</param>
    Public Function Slice(Of T)(source As T(), start As Integer, length As Integer) As T()
        If source Is Nothing Then Return Nothing
        If start < 0 OrElse length <= 0 OrElse start + length > source.Length Then Return New T(-1) {}
        Dim dest(length - 1) As T
        Array.Copy(source, start, dest, 0, length)
        Return dest
    End Function
    ''' <summary>
    ''' 将 Byte 数组按指定编码转成字符串。
    ''' 缺省编码为 UTF-8。
    ''' </summary>
    ''' <param name="bytes">源数组</param>
    ''' <param name="encoding">编码，省略则 UTF-8</param>
    Public Function BytesToString(bytes As Byte(),
                             Optional encoding As Text.Encoding = Nothing) As String
        If bytes Is Nothing OrElse bytes.Length = 0 Then Return ""
        If encoding Is Nothing Then encoding = System.Text.Encoding.UTF8
        Return encoding.GetString(bytes)
    End Function
    Public Function BytesLE4ToInt(buf As Byte()) As Integer
        If buf Is Nothing OrElse buf.Length < 4 Then Return 0
        Return buf(0) Or (buf(1) << 8) Or (buf(2) << 16) Or (buf(3) << 24)
    End Function

    '创建slqit
    Public Sqlitedbpath As String = FileCPatrh & "\SQlitedb\test.db"
    Public SqliteTableName As String = "NT318"
    Public Function ClearDeviceform() As Boolean

        Dim localConn As New DbConnectionStringBuilder
        localConn.Add("Data Source", Sqlitedbpath)
        'localConn.Add("Password", "123456")
        Dim LocalConnString = localConn.ToString()
        '判断有没有文件夹
        If Not Directory.Exists(FileCPatrh & "\SQlitedb\") Then
            Directory.CreateDirectory(FileCPatrh & "\SQlitedb\")
        End If

        Dim selectstr As String = $"CREATE TABLE IF NOT EXISTS {SqliteTableName} (
                                                                id INTEGER PRIMARY KEY AUTOINCREMENT,          -- 替代 BIGINT AUTO_INCREMENT
                                                                `测试时间` TEXT NOT NULL,                     -- DATETIME → TEXT (ISO-8601)
                                                                `测试结果` INTEGER NOT NULL,
                                                                `测试信息` TEXT NOT NULL,
                                                                `软件版本号` TEXT NOT NULL,
                                                                `硬件版本号` TEXT NOT NULL,
                                                                `设备类型ID` INTEGER NOT NULL,
                                                                `厂牌ID` INTEGER NOT NULL,
                                                                `机型ID` INTEGER NOT NULL,
                                                                `UUID` TEXT NOT NULL,
                                                                `设备key` TEXT NOT NULL,
                                                                `设备ClientId` INTEGER NOT NULL,
                                                                `服务器key` TEXT NOT NULL,
                                                                `服务器ClientId` INTEGER NOT NULL,
                                                                `状态机` TEXT NOT NULL,
                                                                `实时值` INTEGER NOT NULL,
                                                                `背景值` INTEGER NOT NULL,
                                                                `基底值` INTEGER NOT NULL,
                                                                `差值` INTEGER NOT NULL,
                                                                `LEL百分比` INTEGER NOT NULL,
                                                                `稳定状态` INTEGER NOT NULL,
                                                                `基底值差值百分比1` INTEGER NOT NULL,
                                                                `基底值差值百分比2` INTEGER NOT NULL,
                                                                `温度` INTEGER NOT NULL,
                                                                `校准结果` INTEGER NOT NULL,
                                                                `温度校准算法选择` INTEGER NOT NULL,
                                                                `回差` INTEGER NOT NULL,
                                                                `传感器极大值` INTEGER NOT NULL,
                                                                `传感器极小值` INTEGER NOT NULL,
                                                                `预热时间_分` INTEGER NOT NULL,
                                                                `ADC_LEV_10` INTEGER NOT NULL,
                                                                `ADC_LEV_0` INTEGER NOT NULL,
                                                                `触发_消抖次数` INTEGER NOT NULL,
                                                                `释放_消抖次数` INTEGER NOT NULL,
                                                                `稳定阈值` INTEGER NOT NULL,
                                                                `报警点提前量` INTEGER NOT NULL,
                                                                `校准超时_秒` INTEGER NOT NULL,
                                                                `IHIOT_心跳包上报间隔` INTEGER NOT NULL,
                                                                `OSD显示模式` INTEGER NOT NULL,
                                                                `检测故障最小值` INTEGER NOT NULL,
                                                                `检测故障最大值` INTEGER NOT NULL,
                                                                `校准最小值_LEV_0` INTEGER NOT NULL,
                                                                `校准最大值_LEV_0` INTEGER NOT NULL,
                                                                `校准最小值_LEV_10` INTEGER NOT NULL,
                                                                `校准最大值_LEV_10` INTEGER NOT NULL,
                                                                `校准最小值_差值` INTEGER NOT NULL,
                                                                `校准最大值_差值` INTEGER NOT NULL,
                                                                `自定义LEV_10_对应的ADC` INTEGER NOT NULL,
                                                                `自定义LEV_0_对应的ADC` INTEGER NOT NULL,
                                                                `泄露恢复正常_条件2` INTEGER NOT NULL,
                                                                `泄露恢复正常_条件2消抖时间_分` INTEGER NOT NULL,
                                                                `设备生产时间` TEXT NOT NULL,
                                                                `RTC时间` TEXT NOT NULL,
                                                                `RTC星期` INTEGER NOT NULL,
                                                                created_at TEXT DEFAULT (datetime('now'))
                                                            );"

        Dim dt As DataTable
        Try
            Using db As New DbExecutor(DbExecutor.DbTypeEnum.Sqlite, LocalConnString)

                db.Open()
                'Try
                '    'Dim vselectstr = $"DELETE FROM {Tftp_Log};"
                '    'db.ExecuteNonQuery(vselectstr)
                'Catch ex As Exception


                'End Try
                dt = db.ExecuteDataTable(selectstr)
                db.Close()
                If IsNothing(dt) Then
                    MsgBox($"数据表创建失败！！！{vbCrLf }")
                    Return False
                Else
                    Return True
                End If
                Return True

            End Using


        Catch ex As Exception
            MsgBox($"数据表创建失败！！！{vbCrLf }原因:{vbCrLf }{ex.Message }")
            Return False
        End Try
    End Function
    Delegate Sub DelegateWriteToTable(dic As Dictionary(Of String, String))
    '写入到表格
    Private Sub WriteToTable(dic As Dictionary(Of String, String))
        If Me.InvokeRequired = True Then
            Dim dd As New DelegateWriteToTable(AddressOf WriteToTable)
            Me.Invoke(dd, {dic})
        Else
            Grid_table.AddItem("")
            Dim con As Integer = 0
            Dim str As String = String.Empty
            For i = 1 To Grid_table.Cols - 1
                str = Grid_table.Cell(0, i).Text
                If dic.ContainsKey(str) Then
                    Grid_table.Cell(Grid_table.Rows - 1, i).Text = dic(str)
                Else
                    con += 1
                End If
            Next
            If dic.Item("测试结果") = "1" Then

                Grid_table.Range(Grid_table.Rows - 1, 1, Grid_table.Rows - 1, Grid_table.Cols - 1).ForeColor = Color.Green
                Grid_table.Range(Grid_table.Rows - 1, 1, Grid_table.Rows - 1, Grid_table.Cols - 1).FontBold = True
            Else
                Grid_table.Range(Grid_table.Rows - 1, 1, Grid_table.Rows - 1, Grid_table.Cols - 1).ForeColor = Color.Red
                Grid_table.Range(Grid_table.Rows - 1, 1, Grid_table.Rows - 1, Grid_table.Cols - 1).FontBold = True

            End If
        End If

    End Sub


    '计算将4个字节合成 Long UTC秒值并转为时间戳
    Private Function CombineFourBytesToLong(ByVal b1 As Byte, ByVal b2 As Byte, ByVal b3 As Byte, ByVal b4 As Byte) As String
        '将4个字节合成 Long UTC秒值并转为时间戳
        Dim temp_val As Long = b1 * 256 * 256 * 256 + b2 * 256 * 256 + b3 * 256 + b4

        '计算UTC时间
        Return $"{DateAndTime.DateSerial(1970, 1, 1).AddSeconds(temp_val).ToString("yyyy-MM-dd HH:mm:ss")}"
    End Function

    '将2个字节 合成十进制数
    Private Function CombineTwoBytesToDecimal(ByVal b1 As Byte, ByVal b2 As Byte) As Integer

        Return b2 * 256 + b1
    End Function
    Private Function CombineTwoBytesToDecimaShort(ByVal b1 As Byte, ByVal b2 As Byte) As Short
        Dim s As Short = b2

        s = s << 8
        s += b1


        Return s
    End Function
    '获取校准结果
    Private Function ReadTheCalibrationResult(Statebyte As Byte) As String
        If Statebyte = 0 Then
            Return "0_校准成功"
        Else
            Return $"{Statebyte}_校准失败"
        End If
    End Function
    '获取状态机状态
    Private Function ReadTheStatus(Statebyte As Byte) As String

        '        状态机
        '#define DevAPP_PowerOn_Start				0x00	//设备状态 - 上电启动
        '#define DevAPP_Preheat						0x01	//设备状态 - 预热
        '#define DevAPP_Normal_Operation				0x02	//设备状态 - 正常监控
        '#define DevAPP_Leak_Detected				0x03	//设备状态 - 检测到泄露
        '#define DevAPP_Alarm						0x04	//设备状态 - 报警
        '#define DevAPP_Malfunction					0x05	//设备状态 - 故障
        '#define DevAPP_Expiration_Of_Life			0x06	//设备状态 - 寿命到期
        '#define DevAPP_Calibration_Mode				0x07	//设备状态 - 校准模式
        '#define DevAPP_Uncalibrated					0x08	//设备状态 - 未校准
        '#define DevApp_Equipment_Outage				0x09	//设备状态 - 220V电源断开
        '#define DevApp_SelfCheck_Mode				0x0A	//设备状态 - 自检模式
        '#define DevApp_Pairing_Mode					0x0B	//设备状态 - 无线配对模式
        Select Case Statebyte
            Case &H0
                Return $"{Hex(Statebyte)}_上电启动"
            Case &H1
                Return $"{Hex(Statebyte)}_预热"
            Case &H2
                Return $"{Hex(Statebyte)}_正常监控"
            Case &H3
                Return $"{Hex(Statebyte)}_检测到泄露"
            Case &H4
                Return $"{Hex(Statebyte)}_报警"
            Case &H5
                Return $"{Hex(Statebyte)}_故障"
            Case &H6
                Return $"{Hex(Statebyte)}_寿命到期"
            Case &H7
                Return $"{Hex(Statebyte)}_校准模式"
            Case &H8
                Return $"{Hex(Statebyte)}_未校准"
            Case &H9
                Return $"{Hex(Statebyte)}_220V电源断开"
            Case &HA
                Return $"{Hex(Statebyte)}_自检模式"
            Case &HB
                Return $"{Hex(Statebyte)}_无线配对模式"


        End Select
    End Function


    Private Function SendPortData1(Name As String, node As SendNode) As String
        Dim sendBytes As Byte()
        Dim result As String = String.Empty
        Try
            '获取发送内容
            sendBytes = GetSendPortData1(Name)
            If sendBytes Is Nothing OrElse sendBytes.Length = 0 Then
                result = $"节点:{Name} :发送数据为空！"
                ' RefreshCaptureText(Color.Red, result)
            End If
            '设置发送节点发送的数据
            node.SetSendData(sendBytes)
            SerialPort.Write(node.SendData, 0, node.SendData.Length)
            '发送刷新对应数值
            node.ResendRefresh()

            'RefreshCaptureText(Color.Green, result)
        Catch ex As Exception
            result = $"发送：【{Name}】失败！{vbCrLf}详情：{vbCrLf}{ex.Message}"
            'RefreshCaptureText(Color.Red, result)
        End Try
        Return result
    End Function
    '获取发送内容
    Public RTC_Time As Date
    Private Function GetSendPortData1(name As String) As Byte()
        Dim sendBytes As Byte()
        If name.Equals("设置RTC时间") Then
            sendBytes = GetSetRTCTime()
        ElseIf name.Equals("设置生产时间") Then
            sendBytes = GetSetUTCTime()
        ElseIf name.Equals("设置设备key") Then
            sendBytes = SetDeviceKey()
        ElseIf CommandSetDic.ContainsKey(name) Then

            sendBytes = CommandSetDic.Item(name)
        End If


        Return sendBytes
    End Function

    Private Function SetDeviceKey() As Byte()
        Dim li As New List(Of Byte)
        li.Add(&HAE)
        li.Add(&H0)  '长度
        li.Add(&H0)  '校验
        li.Add(&H1)  '命令 - 设置参数
        li.Add(&H9)  '参数内容 - 设置RTC时间

        Dim ifnode As (String, SendNode)
        For i As Integer = SendNodeDic.Count - 1 To 0 Step -1
            ifnode = SendNodeDic(i)
            If ifnode.Item1.Equals("获取服务器key") AndAlso ifnode.Item2.RecvStatus = SendNode.RecvStatusEnum.Recv Then
                Exit For
            End If
        Next


        If Not IsNothing(ifnode) AndAlso ifnode.Item1.Equals("获取服务器key") AndAlso ifnode.Item2.RecvStatus = SendNode.RecvStatusEnum.Recv Then
            Dim apinode As Program = ifnode.Item2.RecvDatadic

            li.AddRange(IntTo4BytesLE(apinode.Response.ClientId))
            li.AddRange(StringToBytes(apinode.Response.SecretKey))
            li.Add(&HEA)
            li(1) = li.Count
            li(2) = GetSumCheckMod(li.ToArray, li.Count)
            Return li.ToArray
        Else
            Return Nothing
        End If




    End Function

    Private Sub ToolStripButton2_Click(sender As Object, e As EventArgs) Handles ToolStripButton2.Click



        Dim isvisible As Boolean = False
        If ToolStripButton2.Text.Equals(">>") Then
            '弹窗获取密码
            Dim password As String = InputBox("请输入密码：", "密码验证")
            If Not password.Trim.Equals("Cc2025OK") Then
                Return
            End If
            isvisible = True
            ToolStripButton2.Text = "<<"
        Else

            isvisible = False
            ToolStripButton2.Text = ">>"
        End If

        GroupBox1.Visible = isvisible
        ToolStripLabel1.Visible = isvisible
        T_CommandAlias.Visible = isvisible
        ToolStripLabel2.Visible = isvisible
        ToolStripTextBox2.Visible = isvisible
        ToolStripButton1.Visible = isvisible
        ToolStripComboBox1.Visible = isvisible
        SplitContainer4.Panel1Collapsed = Not isvisible
        ComboBox9.Visible = isvisible
        LblSerialPortBaud.Visible = isvisible
        ToolStripButton4.Visible = isvisible
        ToolStripButton5.Visible = isvisible
        ToolStripButton6.Visible = isvisible
        ToolStripLabel3.Visible = isvisible
        ToolStripTextBox1.Visible = isvisible
        '设置TabControl1 的第1、2个选项卡 显示状态为隐藏或显示
        If (isvisible) Then
            TabPage1.Parent = TabControl1
            TabPage2.Parent = TabControl1
        Else
            TabPage1.Parent = Nothing
            TabPage2.Parent = Nothing
        End If
        For i As Integer = 0 To Grid_table.Cols - 1
            If i > 6 Then
                Grid_table.Column(i).Visible = isvisible
            End If
        Next


    End Sub

    Private Sub ToolStripComboBox1_DropDown(sender As Object, e As EventArgs) Handles ToolStripComboBox1.DropDown
        If IsNothing(CommandSetDic) OrElse CommandSetDic.Count = 0 Then Return
        ToolStripComboBox1.Items.Clear()
        ToolStripComboBox1.Items.AddRange(CommandSetDic.Keys.ToArray())
    End Sub

    Private Sub ProcessTable_CellChange(Sender As Object, e As Grid.CellChangeEventArgs) Handles ProcessTable.CellChange
        'ProcessTable.Cell(0, 0).Text = "序号"
        'ProcessTable.Cell(0, 1).Text = "勾选"
        'ProcessTable.Cell(0, 2).Text = "命令别名"
        'ProcessTable.Cell(0, 3).Text = "命令"
        'ProcessTable.Cell(0, 4).Text = "发送状态"
        If e.Row = 0 Then Return
        Select Case e.Col
            Case 2
                If CommandSetDic.ContainsKey(ProcessTable.Cell(e.Row, 2).Text.Trim) Then
                    Dim strbuf() As Byte = CommandSetDic(ProcessTable.Cell(e.Row, 2).Text.Trim)
                    Dim str As String = ByteArrayToHexString(strbuf)
                    ProcessTable.Cell(e.Row, 3).Text = str
                Else
                    MsgBox("命令别名不存在,请先添加别名和对应命令到命令集，再调用！！")
                    ProcessTable.Cell(e.Row, 2).Text = ""
                End If
        End Select
    End Sub

    Private Sub ToolStripButton5_Click(sender As Object, e As EventArgs) Handles ToolStripButton5.Click
        If ProcessTable.ActiveCell.Row < 1 Then
            ProcessTable.AddItem("")
        Else
            ProcessTable.InsertRow(ProcessTable.ActiveCell.Row, 1)
        End If

    End Sub

    Private Sub ToolStripButton6_Click(sender As Object, e As EventArgs) Handles ToolStripButton6.Click
        If ProcessTable.ActiveCell.Row < 1 Then
            ProcessTable.Row(ProcessTable.Rows - 1).Delete()
        Else
            ProcessTable.Row(ProcessTable.ActiveCell.Row).Delete()
        End If
    End Sub

    Private Sub ToolStripButton4_Click(sender As Object, e As EventArgs) Handles ToolStripButton4.Click
        InitLoadProcessTable(False)
    End Sub

    Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
        My.Settings.SerialPortName = ComboBox8.Text
        My.Settings.SInTime = ToolStripTextBox1.Text
        My.Settings.Save()
        Timer2.Stop()
        Timer1.Stop()
        SaveCommandSetDic()
    End Sub

    Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer2.Tick
        Label39.Text = Now.ToString("yyyy-MM-dd")
        Label40.Text = Now.ToString("HH:mm:ss")
        Select Case Now.DayOfWeek
            Case 0, 7
                Label41.Text = "星期日"
            Case 1
                Label41.Text = "星期一"
            Case 2
                Label41.Text = "星期二"
            Case 3
                Label41.Text = "星期三"
            Case 4
                Label41.Text = "星期四"
            Case 5
                Label41.Text = "星期五"
            Case 6
                Label41.Text = "星期六"
        End Select
        'Label41.Text = $"星期{ Now.DayOfWeek }"
    End Sub
    Public Timediffe As Integer = 2
    Private Sub ToolStripTextBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles ToolStripTextBox1.KeyPress
        '限制输入只能为数字
        If e.KeyChar < "0"c OrElse e.KeyChar > "9"c Then
            e.Handled = True

        End If

    End Sub

    Private Sub ToolStripTextBox1_TextChanged(sender As Object, e As EventArgs) Handles ToolStripTextBox1.TextChanged

        If Integer.TryParse(ToolStripTextBox1.Text, Timediffe) Then
        Else
            ToolStripTextBox1.Text = "2"
            Timediffe = 2
        End If
    End Sub















#End Region




End Class

Public Class SendNode
    '发送时间
    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 RecvDatadic As Object
    Sub New()
        RecvDataLisr = New List(Of Byte())

    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)
        SendData = Mysenddata
        SendInterval = 0
        SendTimeout = 1000
        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 < 3 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




End Class
