2009-08-18 210 views
1

我正在使用串行端口與遠程診斷設備進行通信。SerialPort.DataReceived重複訂閱/取消訂閱

來自遠程設備的響應長度因命令而異,但會提前知道。所以,目前我發送命令並等待接收到所需數量的響應字節。

無論何時我沒有主動請求數據,我都會訂閱'SerialPort.DataReceived'事件。這個事件的處理程序只是簡單地將任何'主動'收到的數據轉儲到日誌中(通常只有在遠程設備意外重啓時纔會收到未經請求的數據,等等)。

在某些情況下,我想以大約60Hz的速率發送命令。

我的問題是,每次我調用我的'SendCommand'方法來主動請求數據時,是否最好取消訂閱/訂閱'SerialPort.DataReceived'事件,還是應該單獨保留事件訂閱,並且只需切換布爾型' TransferInProgress'標誌DataReceived處理程序可用於在我主動請求時忽略傳入數據?

下面是當前實現:

public virtual bool SendCommand(byte[] command, ref byte[] response) { 

    try { 
     TransferInProgress = true; 
     OnTransferStarted(); 

     // temporarily unsubscribe since we're actively soliciting data 
     _port.DataReceived -= 
      new SerialDataReceivedEventHandler(SerialPort_DataReceived); 

     _port.DiscardInBuffer(); 
     _port.Write(command, 0, command.Length); 
     OnCommandSent(command); 

     // read the requested number of response bytes 
     int responseBytesRead = 0; 

     while (responseBytesRead < response.Length) { 
      responseBytesRead += 
       _port.Read(response, responseBytesRead, (response.Length - responseBytesRead)); 
     } 

     OnCommandResponseReceived(response); 
     return true; 
    } 
    catch (Exception ex) { 
     OnCommandSendFailed(ex.Message); 
     return false; 
    } 
    finally { 
     _port.DataReceived += 
      new SerialDataReceivedEventHandler(SerialPort_DataReceived); 
     OnTransferComplete(); 
     TransferInProgress = false; 
    } 
} 

-Trevor

回答

0

你有沒有想過在一個地方處理所有的數據接收?您可以將您發送的命令視爲火災並忘記,解析收到的響應數據。如果響應沒有識別標題,並且知道如何解析它們的唯一方法是知道您發送了哪個命令以及響應的長度,那麼您可以跟蹤隊列中發送的命令。可行的方法是,在您的數據接收處理程序中,您將檢查您正在等待響應的命令隊列,然後像現在一樣解析收到的數據。

長話短說,我會建議在一個地方處理所有傳入的數據。

+0

我喜歡使用隊列來跟蹤命令的想法,但我想知道如何能夠檢測未經請求的數據?我如何能夠確定遠程設備是否使用此方法在命令之間觸發了幾個字節? (注意:遠程設備偶爾會重置自身併發送一些「啓動」類型的字節,不幸的是,我無法控制它)。 – user158485 2009-08-18 16:48:18

+0

您仍然會在您的數據接收處理程序中檢測到未經請求的數據,但您會知道它是未經請求的,因爲您的「SentCommandsQueue」中沒有命令。 我在串口通信中遇到了類似的問題,你必須緩衝你接收到的數據,並將解出重置消息的答案拼湊在一起。一旦你有完整的迴應,從你的隊列中刪除命令。由於重置字節似乎對序列的開頭有某種簽名,因此您應該能夠輕鬆解析它們。 – nathan 2009-08-18 16:57:44

+0

我想我可以實現像這樣的東西。我唯一的預留是復位字節並不總是相同的(按順序或數量),所以如果在正常命令之間接收到復位數據,最終可能會產生意外偏移。這就是說,我相信這個特殊的串口設備有一個選項來啓用命令回顯。在解析響應數組時,我可以使用echo作爲標識頭。 – user158485 2009-08-18 17:59:14

0

如果我理解正確的是簡單地處理在DataReceived處理所有接收數據,或者你有一個其他的選擇我的意見。

如果實際請求之間收到的數據不多,您可以在傳輸請求之前先讀取緩衝區並記錄下來。串行驅動程序接收緩衝區可能足以存儲少量數據。然後發送請求並讀入響應。這很可能是更簡單的方法和更簡單的代碼。

0

我通常會切換布爾值。通過訂閱/取消訂閱,您可能會多次訂閱相同的事件。例如,在您的代碼中,如果OnTransferStarted()引發異常,您將訂閱兩次DataReceived事件。