Как читать сообщение последовательного порта в буфер и анализировать полные сообщения
Я использую следующий код для чтения значений из COM-порта:
Private port As New SerialPort("COM13", 9600, Parity.None, 8, StopBits.One)
Private Sub port_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
Debug.Print(port.ReadExisting())
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
AddHandler port.DataReceived, New SerialDataReceivedEventHandler(AddressOf port_DataReceived)
port.Open()
End Sub
это работает просто отлично, но время от времени он не получает все данные и взамен приводит к двум строкам вместо одного.
пример был бы, если бы com-порт передавал слово "HELLO2YOU", это было похоже на:
HEL
LO2YOU
или
HELLO2
YOU
как я могу разместить буфер там, чтобы убедиться, что он имеет все данные, прочитанные перед отображением это?
спасибо!
2 ответов
вы должны думать о связи последовательного порта как потоковых данных. Каждый раз, когда вы получаете данные, вы должны ожидать, что это может быть полное сообщение, только частичное сообщение или несколько сообщений. Все зависит от того, как быстро поступают данные и как быстро приложение может читать из очереди. Поэтому вы правы, думая, что вам нужен буфер. Однако вы, возможно, еще не осознаете, что нет способа узнать, строго через последовательный порт, где каждое сообщение начинается и заканчивается. Это должно быть обработано через некоторый согласованный протокол между отправителем и получателем. Например, многие люди используют стандартные символы start-of-text (STX) и end-of-text (ETX) для указания начала и окончания каждой отправки сообщения. Таким образом, когда вы получаете данные, вы можете сказать, когда вы получили полное сообщение.
например, если вы использовали символы STX и ETX, вы можете создать такой класс:
Public Class DataBuffer
Private ReadOnly _startOfText As String = ASCII.GetChars(New Byte() {2})
Private ReadOnly _endOfText As String = ASCII.GetChars(New Byte() {4})
Public Event MessageReceived(ByVal message As String)
Public Event DataIgnored(ByVal text As String)
Private _buffer As StringBuilder = New StringBuilder
Public Sub AppendText(ByVal text As String)
_buffer.Append(text)
While processBuffer(_buffer)
End While
End Sub
Private Function processBuffer(ByVal buffer As StringBuilder) As Boolean
Dim foundSomethingToProcess As Boolean = False
Dim current As String = buffer.ToString()
Dim stxPosition As Integer = current.IndexOf(_startOfText)
Dim etxPosition As Integer = current.IndexOf(_endOfText)
If (stxPosition >= 0) And (etxPosition >= 0) And (etxPosition > stxPosition) Then
Dim messageText As String = current.Substring(0, etxPosition + 1)
buffer.Remove(0, messageText.Length)
If stxPosition > 0 Then
RaiseEvent DataIgnored(messageText.Substring(0, stxPosition))
messageText = messageText.Substring(stxPosition)
End If
RaiseEvent MessageReceived(messageText)
foundSomethingToProcess = True
ElseIf (stxPosition = -1) And (current.Length <> 0) Then
buffer.Remove(0, current.Length)
RaiseEvent DataIgnored(current)
foundSomethingToProcess = True
End If
Return foundSomethingToProcess
End Function
Public Sub Flush()
If _buffer.Length <> 0 Then
RaiseEvent DataIgnored(_buffer.ToString())
End If
End Sub
End Class
Я должен также упомяните, что в протоколах связи типично иметь байт контрольной суммы, по которому вы можете определить, было ли сообщение повреждено во время его передачи между отправителем и получателем.
Это вполне нормально, последовательные порты очень медленных устройствах. С как скорость 9600 и машина не слишком сильно увязли, вы получите только один или два байта из порта, когда вы используете ReadExisting(). Отлаживать.Print () выводит Терминатор строки, поэтому вы увидите, что все полученное разбито на части.
самый простой способ исправить это-использовать ReadLine() вместо этого. Это требует, чтобы устройства отправляли специальный символ в конце строки, тот, который соответствует Последовательный порт.Строки значение свойства. Что довольно распространено, линия подачи является шаблоном.
Если нет, то вам понадобится какая-то другая схема буферизации.