2012-10-01 4 views
0

이벤트가 필요합니다. 그 이벤트는 1 바이트가 아닌 전체 라인을 수신 한 후 내 함수를 호출합니다.NewLine에서 SerialPort 이벤트가 필요합니다.

.NET의 SerialPort 객체에는 DataReceived, ErrorReceived, PinChanged 이벤트가 있습니다.

메신저가 DataReceived 이벤트를 사용할 때 "ReceiveByteThreshold"속성에 정의 된 "1"바이트 이후 또는 "x"바이트 후 "실행 중"입니다. 선 길이가 다를 수 있으므로 "x"를 예측할 수 없습니다.

누군가 내게 힌트를 줄 수 있습니까?

LF/CRLF 때까지 바이트를 수집 할 일부 버퍼를 만들거나 문제가 더 나은 접근 방식이 있습니까?

답변

5

이 옵션을 사용할 수 없습니다. 유일한 옵션은 DataReceived 이벤트 처리기 호출을 지연시키는 SerialPort.ReceivedBytesThreshold이며 가변 길이 응답에는 쓸모가 없습니다.

해결 방법은 매우 간단합니다. DataReceived 이벤트 처리기에서 ReadLine()을 호출하면됩니다. 그러면 작업자 스레드에서 차단되어 프로그램에서 진행중인 다른 작업에 영향을주지 않습니다. ReadLine() 호출이 블로킹되는 동안 추가 이벤트가 발생하지 않아도 SerialPort 클래스 내부에서 인터록됩니다. ReadLine()이 영원히 차단되지 않도록 통신이 충분히 안정적이지 않으면 필요한 경우 ReadTimeout 속성을 사용하십시오. 가능한 가장 긴 응답을받을 때 예상 지연 시간의 10 배로 설정하십시오.

+0

나는 그것에 대해 생각하고 있었지만, 여러 사건이 발사 될까봐 걱정했다. 그 매우 귀중한 대답에 감사드립니다. – Kamil

2

직접 처리해야합니다. DataReceived를 사용하고 각 바이트를 확인하십시오. 개행 문자를 얻을 때까지 버퍼에있는 바이트를 수집 한 다음 그 위치에서 버퍼로 처리합니다.

+0

감사합니다. 나는 당신의 대답을 거의 받아 들였지만 더 좋은 방법이 있습니다. 수락 된 답변을 확인하십시오. – Kamil

+0

나는 그 대답도 골랐다. SerialPort에 대한 나의 경험은 조금 제한되어있다. –

0

힌트 :

SerialPort 클래스 ReadLine 메소드 호출의 종료를 해석하는 데 사용되는 값을 설정 한 속성 NewLine있다.

+0

나는 데이터를 보낼 때 그것을 사용하고있다. 어쨌든 감사합니다. – Kamil

+0

나에게 읽어 주시겠습니까? ** ReadLine **을 쓰고 WriteLine이 아닌 – Serge

+0

을 읽었습니다. 그러나 데이터를 기다리지 않고 이벤트를 선호합니다. – Kamil

0

여기 내 구현 방식은 비 차단, 동일한 스레드 솔루션입니다. 그것은 '\ r'과 '\ n'을 기다린 다음, 모든 버퍼링 된 문자를 파싱하기 위해 보내는 아주 기본적인 상태 기계입니다. 상태 기계 자체를 변경하여 원하는 줄 바꿈 값으로 변경할 수 있습니다. 이 접근 방식에서는 OnNewLineReceived 이벤트에 등록하고 SerialStringMessgae 이벤트 핸들러에서 데이터를 처리 할 수 ​​있습니다. 시도/캐치 오버 헤드가 없습니다. 교착 상태는 없습니다.

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace NonBlockingSerialPortReadLine 
{ 
    public partial class Form1 : Form 
    { 
    System.IO.Ports.SerialPort sp = new System.IO.Ports.SerialPort(); 
    public event EventHandler OnNewLineReceived; 
    System.Windows.Forms.Timer NewDataTimer = new System.Windows.Forms.Timer(); 
    int StateMachine = 0; 
    StringBuilder stringBuffer = new StringBuilder(); 

    public Form1() 
    { 
     InitializeComponent(); 
     InitTimer(); 
     InitOnNewLineReceived(); 
    } 

    private void InitTimer() 
    { 
     NewDataTimer.Interval = 50; 
     NewDataTimer.Tick += NewDataTimer_Tick; 
    } 

    private void InitOnNewLineReceived() 
    { 
     OnNewLineReceived += Form1_OnNewLineReceived; 
    } 

    void Form1_OnNewLineReceived(object sender, EventArgs e) 
    { 
     SerialStringMessgae STM = e as SerialStringMessgae; 
     string messgae = STM.message; 

     // PARSE YOU MESSAGE HERE - the debug line below is not mandatory 

     System.Diagnostics.Debug.WriteLine(messgae); 
    } 

    class SerialStringMessgae : EventArgs 
    { 
     public string message; 
    } 

    private void StartListeningButton_Click(object sender, EventArgs e) 
    { 
     StartListeningButton.Enabled = false; 
     sp = new System.IO.Ports.SerialPort("COM4",57600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One); 
     try 
     { 
      sp.Open(); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.ToString()); 
      return; 
     } 
     if (sp.IsOpen) 
     { 
      NewDataTimer.Enabled = true; 
     } 

    } 

    void NewDataTimer_Tick(object sender, EventArgs e) 
    { 
     string newData = sp.ReadExisting(); 
     foreach (char c in newData) 
     { 
      switch (StateMachine) 
      { 
       case 0: 
        // waiting for '\r' 
        if (c == '\r') 
        { 
         StateMachine = 1; 
        } 
        else 
        { 
         stringBuffer.Append(c); 
        } 
        break; 
       case 1: 
        // waiting for '\n' 
        if (c == '\n') 
        { 
         if (OnNewLineReceived != null) 
         { 
          SerialStringMessgae STM = new SerialStringMessgae(); 
          STM.message = stringBuffer.ToString(); 
          OnNewLineReceived(this, STM); 
         } 
        } 
        // after parsing the message we reset the state machine 
        stringBuffer = new StringBuilder(); 
        StateMachine = 0; 
        break; 
      } 
     } 
    } 

} 
}