Imports System.IO.Ports
Imports System.Text
Imports UTS_Core.DebugLog

Namespace UTSModule.Test
    Public Class UtsComPort
        ''' <summary>通讯串口</summary>
        Private ReadOnly Property Comport As SerialPort

        ''' <summary>接收起始时间</summary>
        Private _receiveStartTime As DateTime

        ''' <summary>接收到的字符串</summary>
        Private ReadOnly _receiveString As New StringBuilder

        ''' <summary>接收到的经过处理后的合法数据队列</summary>
        Public CacheData As New Queue(Of UtsComPortData)

        Sub New()
            Comport = New SerialPort()
            AddHandler Comport.DataReceived, AddressOf ComPort_DataReceived

            ReceivedData = New UtsComPortData()
        End Sub

        ''' <summary>
        ''' 获取所有串口名
        ''' </summary>
        ''' <returns></returns>
        Shared Function GetPortNames() As String()
            Return SerialPort.GetPortNames()
        End Function

        ''' <summary>
        ''' 打开串口
        ''' </summary>
        ''' <param name="portName"></param>
        ''' <param name="baudRate"></param>
        Public Function OpenSerialPort(portName As String, baudRate As Integer) As Boolean
            Try
                If Comport.IsOpen Then Comport.Close()
                With Comport
                    .PortName = portName '串口名
                    .BaudRate = baudRate '波特率
                    .DataBits = 8 '数据位
                    .StopBits = StopBits.One '停止位
                    .Parity = Parity.None  '偶校验
                    .RtsEnable = True
                    .Open()
                End With
            Catch ex As Exception
                Console.WriteLine($"打开测试串口失败!原因:{ex.Message}。")
                Return False
            End Try
            Return True
        End Function

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

            Return True
        End Function

        Public Function SendText(sendString As String) As Boolean
            Try
                Comport.Write(sendString)
            Catch ex As Exception
                Console.WriteLine($"Send Error,原因：{ex.Message}")
                Return False
            End Try
            Return True
        End Function

        Public Function SendText(sendData As UtsComPortData) As Boolean
            If sendData Is Nothing Then Throw New Exception($"SendTest：SendData Is Nothing")

            Return SendText(sendData.ToString())
        End Function

        Public Function SendText(fromAddress As String, toAddress As String, command As String, params As List(Of String)) As Boolean
            Return SendText(UtsComPortData.ConvertToString(fromAddress, toAddress, command, params))
        End Function

        Public Function SendTextAppendCrLf(sendData As UtsComPortData) As Boolean
            If sendData Is Nothing Then Throw New Exception($"SendTest：SendData Is Nothing")

            Return SendText($"{sendData}{vbCrLf}")
        End Function

        Public Function SendTextAppendCrLf(fromAddress As String, toAddress As String, command As String, params As List(Of String)) As Boolean
            Return SendText($"{UtsComPortData.ConvertToString(fromAddress, toAddress, command, params)}{vbCrLf}")
        End Function


        Private Function ReceiveData() As Byte()
            Static bytes As Integer = 0
            Try
                bytes = Comport.BytesToRead
            Catch ex As Exception
                Console.WriteLine($"UtsComport BytesToRead Error:{ex.Message}")
                Return New Byte() {}
            End Try

            Dim receiveBuffer(bytes - 1) As Byte
            Try
                Comport.Read(receiveBuffer, 0, bytes)
            Catch ex As Exception
                Console.WriteLine($"UtsComport ReceiveData Error:{ex.Message}")
                Return New Byte() {}
            End Try

            Return receiveBuffer
        End Function

        Private Function DealReceivedData(receiveBuffer() As Byte) As Boolean
            If receiveBuffer.Length <= 0 Then Return True
            If receiveBuffer(receiveBuffer.Length - 1) = 10 Then '接收到换行符，接收完成

                _receiveString.Append(Encoding.UTF8.GetString(receiveBuffer, 0, receiveBuffer.Length))

                Dim tmpString() As String = _receiveString.ToString().Replace(ControlChars.Cr, String.Empty).Split(New Char() {ControlChars.Lf}, StringSplitOptions.RemoveEmptyEntries)

                For Each str As String In tmpString
                    Try
                        CacheData.Enqueue(UtsComPortData.ConvertFromString(str))

                        If CacheData.Count > 64 Then CacheData.Dequeue() '缓存数据队列过多，移除头部缓存
                    Catch ex As Exception
                        ApplicationLog.WriteWarningLog($"ComportData ConvertString Error,String:{str} Error:{ex.Message}")
                        Console.WriteLine($"ComportData ConvertString Error,String:{str} Error:{ex.Message}")
                    End Try
                Next

                _receiveString.Clear() '处理完成清空缓存
                _receiveStartTime = Now

            Else
                If _receiveString.Length = 0 Then '单包未接收完全，记录起始时间
                    _receiveStartTime = Now
                End If

                _receiveString.Append(Encoding.UTF8.GetString(receiveBuffer, 0, receiveBuffer.Length))

                '_receiveStatus = ReceiveStatusEnum.Receiving

                '超过最大缓冲长度,则先处理
                '超时仍旧未接收完全,则先处理
            End If

            Return True
        End Function

        Private Sub ComPort_DataReceived(sender As Object, e As SerialDataReceivedEventArgs)
            Dim receiveBuffer() As Byte = ReceiveData()

            DealReceivedData(receiveBuffer)
        End Sub

        ''' <summary>
        ''' 接收分析后的数据
        ''' </summary>
        ''' <returns></returns>
        Public ReadOnly Property ReceivedData As UtsComPortData


        Public Function ComportName() As String
            Return Comport.PortName
        End Function

        Public Function ComportBaudRate() As Integer
            Return Comport.BaudRate
        End Function

        Public Function StartReceiveTime() As DateTime
            Return _receiveStartTime
        End Function
    End Class
End Namespace