2012-11-03 34 views
1

我嘗試從我的Java串口讀取二進制協議。我使用RXTX library從串口讀取數據。如何從InputStream讀取二進制協議?

該協議是用於GPS接收機的SiRF二進制協議。結構是:

  • 頭兩個字節是0XA0和0xA2,它定義一個數據幀
  • 下兩個字節是有效載荷長度n
  • 下一個n個字節是有效載荷
  • 最後的開始兩個字節是0xB0和0xB3,它們定義了數據幀的末尾

雖然這個結構非常簡單,但我無法正確讀取數據。我嘗試兩種不同的方式:

  1. 我寫了一個線程,它從InputStream讀取和輸入與0XA0進行比較。如果匹配,則線程讀取下一個字節並將其與0xA2進行比較。如果再次匹配,則它讀取下兩個字節並計算有效載荷長度。之後,它讀取長度爲n字節的有效載荷。最後,它讀取最後兩個字節,並將它們與0xB0和0xB3進行比較。當一切都匹配時,它會從輸入創建一個十六進制字符串並將其保存到隊列中。這裏是我的代碼:

    try { 
        byte[] size = new byte[2]; 
        byte[] checkSum = new byte[2]; 
        byte[] packet; 
        int bytesRead = -1; 
        while (in.available() > 0) { 
         if (getInput() == 0xA0) { 
          if (getInput() == 0xA2) { 
           System.out.print("160,162,"); 
           bytesRead = in.read(size); 
           int payLoadLength = (size[0] << 8) | (size[1] & 0xFF); 
           byte[] payload = new byte[payLoadLength]; 
           bytesRead = in.read(payload); 
           bytesRead = in.read(checkSum); 
           if (getInput() == 0xB0) { 
            if (getInput() == 0xB3) { 
           System.out.println("out"); 
           packet = new byte[2 + 2 + payLoadLength + 2 + 2]; 
           packet[0] = (byte) START_1; 
           packet[1] = (byte) START_2; 
           packet[2] = size[0]; 
           packet[3] = size[1]; 
           for (int i = 0; i < payload.length; i++) { 
            packet[i + 4] = payload[i]; 
           } 
           packet[packet.length - 4] = checkSum[0]; 
           packet[packet.length - 3] = checkSum[1]; 
           packet[packet.length - 2] = (byte) END_1; 
           packet[packet.length - 1] = (byte) END_2; 
           StringBuffer hexString = new StringBuffer(); 
           int[] output = new int[packet.length]; 
           for (int i = 0; i < packet.length; i++) { 
            output[i] = 0xFF & packet[i]; 
            hexString.append(Integer.toHexString(output[i])); 
           } 
           TransportMessage tm = new TransportMessage(hexString.toString()); 
           boolean b = queue.offer(tm); 
           System.out.println(hexString.toString().toUpperCase()); 
           if(!b) 
            System.err.println("TransportMessageQueue voll!"); 
          } 
         } else { 
          System.out.println(); 
         } 
        } 
    } 
        } 
    } catch (IOException e) { 
        System.out.println(e); 
    } 
    

    getInput()只是讀取來自InputStream一個字節。

  2. 我使用了RXTX庫中的SerialPortEventListener。每當串口發生什麼事情時,SerialPortEvent就會被觸發,並以類似於第一種方法的方式讀取數據。

爲了調試原因,我添加了一些System.out.println()來電顯示究竟是由線程讀取,似乎我的思念幾乎通過InputStream sended所有數據幀的一半。

我現在的問題是:從InputStream讀取這樣的協議的最佳方式是什麼?在我看來,我必須讓我的閱讀努力與串口數據同步,但我不知道如何在Java中做到這一點。

+1

java.io.DataInputStream用於這些任務。 –

回答

1

如果您正在使用RXTX你可以設置一個監聽器asyncronously數據可用時它會通知你:

serial.notifyOnDataAvailable(true); 
serial.addEventListener(this); 

public void serialEvent(final SerialPortEvent arg0) { 
    try { 
     if (arg0.getEventType() == SerialPortEvent.DATA_AVAILABLE) { 
      //read from the input stream; 
     } 
    } catch (final Exception e) { 
     e.printStackTrace(); 
    } 
} 

在一般情況下,當您從輸入讀取流你應該抽象的「分組的概念數據「並且不使用」可用「功能 - 只需從數據包中讀取足夠的數據以確定其長度,然後使用」read(byte [])「將完整數據包讀入緩衝區。 (在更高級的說明中,「讀取」可以讀取比需要更少的字節,因此應該在循環中使用它)。

+0

我已經試過了。應該已經更清楚了。這樣,我仍然缺少一些數據框。 – htz

+0

我發現問題:它是圍繞閱讀過程的附加循環'while(in.available()> 0){}'。你寫了「當數據可用時異常通知你」,這讓我感到懷疑......擦除這個循環後,它似乎按預期工作。謝謝! – htz

+0

是的,我從未設法充分利用「可用」功能。 – thedayofcondor