2012-07-12 17 views
6

पार्स आउट कर मैं एक कॉम बंदरगाह से मूल्यों को पढ़ने के लिए निम्नलिखित कोड का उपयोग कर रहा:कैसे बफर में सीरियल पोर्ट संचार पढ़ना और पूरा संदेशों

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 

यह सिर्फ ठीक काम करता है, लेकिन हर अब और फिर इसे पाने does not को सभी डेटा और बदले में परिणाम केवल एक के बजाय दो तारों में होते हैं।

एक उदाहरण अगर कॉम पोर्ट शब्द पर भेज रही थी होगा "HELLO2YOU" यह देखने के लिए किया गया था की तरह:

HEL 
LO2YOU 

या

HELLO2 
YOU 

कैसे मैं एक बफर में वहाँ जगह कर सकते हैं ताकि यह सुनिश्चित करता है कि इसे प्रदर्शित करने से पहले सभी डेटा पढ़े गए हैं?

धन्यवाद!

उत्तर

9

आपको स्ट्रीमिंग डेटा के रूप में सीरियल पोर्ट संचार के बारे में सोचना होगा। जब भी आप डेटा प्राप्त करते हैं, आपको उम्मीद करनी होगी कि यह एक पूरा संदेश हो सकता है, केवल आंशिक संदेश या एकाधिक संदेश हो सकता है। यह सब इस बात पर निर्भर करता है कि डेटा कितनी तेजी से आ रहा है और कतार से आप कितनी तेजी से आवेदन कर सकते हैं। इसलिए, आप सोच रहे हैं कि आपको बफर चाहिए। हालांकि, आप अभी तक क्या महसूस नहीं कर रहे हैं, यह है कि सीरियल पोर्ट के माध्यम से सख्ती से जानने का कोई तरीका नहीं है, जहां प्रत्येक संदेश शुरू होता है और समाप्त होता है। इसे प्रेषक और रिसीवर के बीच कुछ प्रोटोकॉल पर सहमत होने के माध्यम से संभाला जाना है। उदाहरण के लिए, कई लोग प्रत्येक संदेश भेजने की शुरुआत और समाप्ति को इंगित करने के लिए मानक स्टार्ट-ऑफ-टेक्स्ट (एसटीएक्स) और एंड-ऑफ-टेक्स्ट (ईटीएक्स) वर्णों का उपयोग करते हैं। इस तरह, जब आप डेटा प्राप्त करते हैं, तो आप बता सकते हैं कि आपको एक पूर्ण संदेश कब प्राप्त हुआ है।

उदाहरण के लिए

, यदि आप एसटीएक्स और 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 

मैं भी कि, संचार प्रोटोकॉल में, यह है जिसके द्वारा एक checksum बाइट के लिए विशिष्ट है उल्लेख करना चाहिए प्रेषक और रिसीवर के बीच अपने संचरण के दौरान संदेश दूषित हो सकता है या नहीं।

3

यह काफी सामान्य है, सीरियल पोर्ट बहुत धीमी डिवाइस हैं। 9600 की तरह बॉड्रेट्स के साथ और मशीन बहुत अधिक नहीं हो जाती है, जब आप ReadExisting() का उपयोग करते हैं तो आपको बंदरगाह से केवल एक या दो बाइट मिलेंगे। डीबग.प्रिंट() एक लाइन टर्मिनेटर आउटपुट करता है ताकि आप देखेंगे कि टुकड़ों में जो कुछ भी टूटा हुआ है।

इसके बजाय इसे ठीक करने का सबसे आसान तरीका ReadLine() का उपयोग कर है। यह आवश्यक है कि डिवाइस लाइन के अंत में एक विशेष चरित्र भेजता है, जो सीरियलपोर्ट से मेल खाता है। न्यूलाइन संपत्ति मूल्य। जो काफी आम है, एक लाइन फीड बॉयलरप्लेट है।

यदि नहीं तो आपको किसी अन्य प्रकार की बफरिंग योजना की आवश्यकता होगी।

+0

हंस सही है कि रीडलाइन() एक "न्यूलाइन" मान द्वारा समाप्त किए गए पूर्ण संदेश प्राप्त करने का एक आसान तरीका है। हालांकि, मैं रीडलाइन का उपयोग करने से बचूंगा क्योंकि इसे सामान्य रूप से अवरुद्ध करने वाले फ़ंक्शन के रूप में कार्यान्वित किया जाता है और आपके जीयूआई और अन्य कार्यों के प्रदर्शन को कम कर देगा। आम तौर पर जब तक मैं समाप्ति चरित्र प्राप्त नहीं करता तब तक मैं वर्णों को एक सरणी में बफर कर दूंगा, फिर कमांड पार्सर को कॉल करें। – Jeff

+0

नहीं, जब आप इसे DataReceived ईवेंट हैंडलर में नहीं कहते हैं, तो यह थ्रेडपूल थ्रेड पर चलता है। –

संबंधित मुद्दे