Imports System.IO.Ports

Namespace UTSModule.Test.Command.ComPortCommand

    Public Class ComPort
        Private _serialPort As SerialPort '串口操作对象

        ''' <summary>
        ''' 串口名
        ''' </summary>
        ''' <returns></returns>
        Public Property PortName As String

        ''' <summary>
        ''' 串口别名
        ''' </summary>
        ''' <returns></returns>
        Public Property PortAlias As String

        ''' <summary>
        ''' 默认接收超时时间,通讯时超时设置为0时使用该值
        ''' </summary>
        ''' <returns></returns>
        Public Property DefaultTimeout() As Integer

        ''' <summary>
        ''' 串口接受单字节间隔接受超时
        ''' </summary>
        Private recevieInterval As Integer

        Sub New()
            _serialPort = New SerialPort

            PortName = String.Empty
            PortAlias = String.Empty
        End Sub

        Sub New(name As String, [alias] As String)
            PortName = name
            PortAlias = [alias]
        End Sub

        ''' <summary>
        ''' 当前串口是否已经打开
        ''' </summary>
        ''' <returns></returns>
        Public Function IsOpen() As Boolean
            If _serialPort Is Nothing Then Return False
            Return _serialPort.IsOpen
        End Function

        Public Function InitializePort(comParam As String) As Boolean
            Dim param() As String = comParam.Split(New Char() {","c, ":"c, "："c, "，"c})
            _serialPort = New SerialPort()
            With _serialPort
                _serialPort.ReceivedBytesThreshold = 1
                recevieInterval = 50
                .PortName = PortName
                If Integer.TryParse(param(0), .BaudRate) = False Then Return False '波特率
                If Integer.TryParse(param(2), .DataBits) = False Then Return False '数据位
                If [Enum].TryParse(param(3), .StopBits) = False Then Return False '停止位

                Select Case param(1).ToUpper
                    Case "N"
                        .Parity = Parity.None    '无校验
                    Case "O"
                        .Parity = Parity.Odd    '奇校验
                    Case "E"
                        .Parity = Parity.Even    '偶校验
                    Case "M"
                        .Parity = Parity.Mark    '保留为1
                    Case "S"
                        .Parity = Parity.Space     '保留为0
                    Case Else
                        Return False
                End Select
            End With

            Return True
        End Function

        Public Function Open() As Boolean
            If _serialPort Is Nothing Then Return False
            If _serialPort.IsOpen Then Return True
            Try
                _serialPort.Open()
            Catch ex As Exception
                Return False
            End Try
            Return True
        End Function

        Public Function Close() As Boolean
            If _serialPort Is Nothing Then Return True
            If IsOpen() = False Then Return True
            Try
                _serialPort.Close()
            Catch ex As Exception
                Return False
            End Try
            Return True
        End Function

        Public Function Write(sendText As String, Optional sendType As SendTypes = SendTypes.StringAndCrlf) As Boolean
            Dim result As Boolean = False
            Select Case sendType
                Case SendTypes.String
                    result = WriteText(sendText)
                Case SendTypes.StringAndCrlf
                    sendText = sendText & vbCrLf
                    result = WriteText(sendText)
                Case SendTypes.ByteString
                    result = WriteBytes(sendText)
            End Select

            Return result
        End Function


        Public Function WriteText(text As String) As Boolean
            Dim buf() As Byte = System.Text.Encoding.UTF8.GetBytes(text)
            Try
                _serialPort.Write(buf, 0, buf.Length)
                While _serialPort.BytesToWrite > 0
                    Threading.Thread.Sleep(1)
                End While
            Catch ex As Exception
                Return False
            End Try
            Return True
        End Function

        Public Shared Function HexStringToBytes(hexString As String) As Byte()
            Dim hex() As String = hexString.Split(New Char() {" "c}, StringSplitOptions.RemoveEmptyEntries)
            Dim buf(hex.Length - 1) As Byte
            For i As Integer = 0 To hex.Length - 1
                buf(i) = Convert.ToByte(hex(i), 16)
            Next
            Return buf
        End Function

        Public Function WriteBytes(hexString As String) As Boolean
            Try
                Dim buf() As Byte = HexStringToBytes(hexString)
                _serialPort.Write(buf, 0, buf.Length)
            Catch ex As Exception
                Return False
            End Try
            Return True
        End Function

        Public Function WriteBytes(buf() As Byte) As Boolean
            Try
                _serialPort.Write(buf, 0, buf.Length)
            Catch ex As Exception
                Return False
            End Try
            Return True
        End Function

        Public Function ReadBytes(timeout As Integer) As Byte()
            '处理在512内的字节的接收包有效
            If _serialPort Is Nothing Then Return New Byte() {}

            Static watch As New Stopwatch
            Dim receiveBuf As New List(Of Byte)
            Dim length As Integer
            Dim readTime As Long = 0

            watch.Restart()
            While timeout > watch.ElapsedMilliseconds
                Try
                    length = _serialPort.BytesToRead

                    If length > 0 Then
                        Dim buf(length - 1) As Byte
                        _serialPort.Read(buf, 0, buf.Length)

                        receiveBuf.AddRange(buf)

                        readTime = watch.ElapsedMilliseconds
                    Else
                        If receiveBuf.Count > 0 Then
                            If watch.ElapsedMilliseconds - readTime > recevieInterval Then
                                Exit While
                            End If
                        End If
                    End If
                Catch ex As Exception
                    Return New Byte() {}
                End Try

                Threading.Thread.Sleep(1)
            End While
            watch.Stop()

            Return receiveBuf.ToArray()
        End Function

        ''' <summary>
        ''' 清空接受缓冲区内容
        ''' </summary>
        Public Sub ClearRecvCache()
            Try
                _serialPort.DiscardInBuffer()
                _serialPort.DiscardOutBuffer()
            Catch ex As Exception
                Console.WriteLine($"ClearRecvCache Error:{ex.Message}")
            End Try
        End Sub

        Public Function NameEqual(name As String) As Boolean
            If String.IsNullOrWhiteSpace(name) Then Return False
            If String.Compare(PortName, name, True) <> 0 Then Return False
            Return True
        End Function

        Public Function AliasEqual(name As String) As Boolean
            If String.IsNullOrWhiteSpace(name) Then Return False
            If String.Compare(PortAlias, name, True) <> 0 Then Return False
            Return True
        End Function

        Enum SendTypes
            ''' <summary>字符串发送</summary>
            [String]

            ''' <summary>字符串发送，添加回车换行</summary>
            StringAndCrlf

            ''' <summary>十六进制字符串发送</summary>
            ByteString
        End Enum
    End Class
End Namespace