2012-11-03 4 views
1

Java의 직렬 포트에서 이진 프로토콜을 읽으려고합니다. 나는 RXTX library을 사용하여 직렬 포트에서 읽습니다.InputStream에서 이진 프로토콜을 읽는 방법?

이 프로토콜은 GPS 수신기 용 SiRF 바이너리 프로토콜입니다. 구조는 다음

  • 제 2 바이트
  • 다음 2 바이트
  • 다음 n 바이트가 페이로드
  • 마지막에게있는 페이로드 길이 n에게되는 데이터 프레임의 시작을 정의 내지 0xA0 및 0xA2, 아르 2 바이트는 데이터 프레임의 끝을 정의하는 0xB0 및 0xB3입니다.

이 구조는 매우 간단하지만 데이터를 올바르게 읽을 수는 없습니다.

  1. 나는 InputStream에서 읽어 내지 0xA0로 입력을 비교하는 스레드를 썼다 : 나는 두 가지 방법을 시도했다. 이 값이 일치하면 스레드는 다음 바이트를 읽고 0xA2와 비교합니다. 이 값이 다시 일치하면 다음 2 바이트를 읽고 페이로드 길이를 계산합니다. 그 후 길이가 n 바이트 인 페이로드를 읽습니다. 마침내 마지막 2 바이트를 읽고 0xB0 및 0xB3과 비교합니다. 모든 것이 일치하면 입력에서 16 진수 문자열을 만들어 대기열에 저장합니다.

    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가 실행되고 첫 번째 방법과 비슷한 방식으로 데이터를 읽습니다.

디버깅 이유로 나는 정확히 스레드에 의해 읽고 내가 InputStream를 통해 발송에 실패 모든 데이터 프레임의 거의 절반을 잃었 것으로 보인다 무엇 보여 System.out.println() 여러 통화를 추가했다.

내 질문은 : InputStream에서 그런 프로토콜을 읽는 가장 좋은 방법은 무엇입니까? 필자는 필자의 독서 노력을 시리얼 포트의 데이터와 동기화시켜야한다고 생각한다.하지만 자바에서 어떻게할지는 모른다.

+1

이러한 작업에는 java.io.DataInputStream이 사용됩니다. –

답변

1

것은 당신이 데이터를 사용할 수 asyncronously 때 통지하는 리스너를 설정할 수 있습니다 RXTX를 사용하는 경우 :

일반적으로
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(); 
    } 
} 

, 당신은 입력에서 읽을 때해야 추상적의 패킷 "의 개념을 스트리밍 데이터 "를 사용하지 않고"available "함수를 사용하지 않습니다. 패킷의 길이를 결정할 수있을 정도로 충분히 읽은 다음 버퍼에 전체 패킷을 읽는 데"read (byte []) "를 사용하십시오. (보다 고급 노트에서 "read"는 필요한 것보다 적은 바이트를 읽을 수 있으므로 루프에서 사용해야합니다).

+0

나는 이미 이것을 시도했다. 에서 그것을 분명히 했음에 틀림 없다. 이렇게하면 데이터 프레임 중 일부가 여전히 누락되었습니다. – htz

+0

문제점을 발견했습니다. 읽기 프로세스를 둘러싼 부가적인 while (in.available()> 0) {}'루프가있었습니다. 당신은 "데이터를 사용할 수있을 때 비동기 적으로 사용자에게 알립니다"라고 썼습니다. 이걸 보면 의심 스럽습니다 ...이 루프를 지우고 나면 의도 한대로 작동하는 것 같습니다. 감사! – htz

+0

예, "사용 가능한"기능을 제대로 활용하지 못했습니다. – thedayofcondor

관련 문제