2014-12-30 4 views
0

좋아요, 제 문제로 가능한 한 명확하게하려고 노력하겠습니다. 저속 라디오 링크를 통해 직렬 데이터를 전송하고 있습니다 (라스베리 파이의 UART 컨트롤러 및 가정용 라디오 사용). 요구 사항의 철자가 이고 범위가이고 속도가 그다지 중요하지 않은 매우 구체적인 프로젝트입니다. 프로그램 (Radio.java)이 두 개의 스레드를 실행 중입니다. 하나의 스레드 (수신기)는 TCP 소켓을 사용하여 다른 프로그램에서 원격 측정 데이터를 수신합니다 (실제로는 매우 고속입니다. 실제로는 100mbit입니다). 이 스레드는 다른 스레드 (송신기)가이 데이터에 도달 할 수 있도록 ArrayBlockingQueue (크기 = 1)의 TCP 소켓에서 수신 한 데이터를 지속적으로 저장합니다. 수신자 스레드가 데이터를받는 속도는 꽤 빠릅니다. 이제, 송신기 스레드가 데이터 을 전송하기를 원합니다. 완료되면 수신자 스레드로부터 최신 데이터를 다시 얻고 저속 무선 링크를 통해 다시 전송하기를 원합니다.다른 스레드의 데이터 전송, Java 및 RXTX 라이브러리와의 느린 직렬 링크

  1. 수신기 스레드에서 최신 데이터를 가져옵니다

  2. 전송 무선 링크합니다 (하여 SerialPort를 사용하여)

  3. 돈을 통해 데이터 ' 그래서 송신기 스레드에서 나는 다음과 같이 작업 할 데이터가 실제로 전송 될 때까지 아무 일도하지 마십시오.

  4. 반복.

이제 프로그램을 실행할 때 Receiver-thread에 관한 모든 것이 잘 작동합니다. 하지만 송신기 스레드 내부에서 "this.out.write (output.getBytes());" 몇 밀리 초 내에 OutputStream 내부에 모든 것을 넣은 다음 다시 똑같은 작업을 수행합니다. 데이터는 전송 될 가능성이 없습니다! 여기에 내가 (단지 "SerialWriter"-thread 사용) 예를 시도했습니다

: http://rxtx.qbang.org/wiki/index.php/Two_way_communcation_with_the_serial_port

그리고 모든 50baud에 잘 전달 근무 -text 긴 "Lirum Ipsum 제품"을 사용. 그래서 기본적으로, 내 프로그램에서 System.in.read> -1을 사용하는 것과 동일한 동작이 필요합니다. (차단하고있는 이유는 그것이 작동하는 이유입니다).

어떻게해야합니까?

2015년 1월 1일 편집 내가 문제를 발견했습니다

을 BEGIN! SRobertz가 나를 올바른 방향으로 인도합니다! 문제는 실제로 UART 버퍼에 쓰기 속도가 아닙니다. "TwoWayComm"-example과 내 자신의 코드를 실행하는 것의 차이점은 Raspberry Pi의 UART-RX-port에 연결된 GPS를 실행하고 있다는 것입니다. GPS에서 데이터를 읽으려면 "GPSD"- 소프트웨어 (JSON 형식의 데이터를 출력 함)를 사용하십시오. GPSD- 소프트웨어는 9600baud (특히이 GPS 장치 용)로 GPS에 연결하는 반면, 동일한 포트에서 (GPSD가 실행중인 열린 연결을 닫지 않고) 50 보오 전환합니다! 두 가지 다른 전송 속도로 UART를 열려고하면 모든 것을 엉망으로 만드는 것입니다.

  1. 열기 UART 9600 보드에
  2. 읽기 GPS 데이터
  3. UART에 50 보드에
  4. 전송 원격 측정 데이터를 UART
  5. 열기 UART를 닫습니다 : I 있도록 나는 코드를 다시 작성했습니다
  6. 닫기 UART
  7. 반복

이제 모든 것이 여기에 ...

2015년 1월 1일 편집 END

그래서 ... 마법처럼 작동하는 코드입니다 :

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.OutputStream; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.util.concurrent.ArrayBlockingQueue; 

import gnu.io.CommPort; 
import gnu.io.CommPortIdentifier; 
import gnu.io.SerialPort; 

public class RADIO { 
    ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(1); 

    void connect(String portName) throws Exception { 

     CommPortIdentifier portIdentifier = CommPortIdentifier 
       .getPortIdentifier(portName); 
     if (portIdentifier.isCurrentlyOwned()) { 
      System.out.println("Error: Port is currently in use"); 
     } else { 
      int timeout = 2000; 
      CommPort commPort = portIdentifier.open(this.getClass().getName(), 
        timeout); 

      if (commPort instanceof SerialPort) { 
       SerialPort serialPort = (SerialPort) commPort; 
       serialPort.setSerialPortParams(50, SerialPort.DATABITS_7, 
         SerialPort.STOPBITS_2, SerialPort.PARITY_NONE); 

       // Open outputstream to write to the serial port 
       OutputStream out = serialPort.getOutputStream(); 

       (new Thread(new Receiver(queue))).start(); 
       (new Thread(new Transmitter(out, queue))).start(); 

      } else { 
       System.err.println("Error: Not serial port."); 
      } 
     } 
    } 

    public static class Receiver implements Runnable { 
     OutputStream out; 
     protected ArrayBlockingQueue<String> queue = null; 

     public Receiver(ArrayBlockingQueue<String> queue) { 
      this.queue = queue; 
     } 

     public void run() { 
      // Open TCP-connection 
      try { 
       ServerSocket serverSocket = new ServerSocket(1002); 

       Socket clientSocket = serverSocket.accept(); // Wait for the client to start up 
       BufferedReader in = new BufferedReader(new InputStreamReader(
         clientSocket.getInputStream())); 
       String inputLine, outputLine; 

       while ((inputLine = in.readLine()) != null) { 
        queue.clear(); 
        queue.put(inputLine); 
       } 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

     } 
    } 

    public static class Transmitter implements Runnable { 
     OutputStream out; 
     protected ArrayBlockingQueue<String> queue = null; 
     String output = ""; 

     public Transmitter(OutputStream out, ArrayBlockingQueue<String> queue) { 
      this.out = out; 
      this.queue = queue; 
     } 

     public void run() { 
      try { 
       while (true) { 
        output = queue.take(); 
        this.out.write(output.getBytes()); 
       } 

      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 

    } 

    public static void main(String[] args) { 
     try { 
      (new RADIO()).connect("/dev/ttyAMA0"); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

답변

1

(작은주의 :

우선 문제를 분리하기 위해 this.out.write... 다음에 송신기 스레드에 꽤 긴 sleep을 넣을 것입니다. 그 문제는 시리얼 포트가 이 될 때까지 기다리지 않고 전송을 마칩니다.

이 작동하는 경우에, 당신은 SerialPortEventListener를 추가하고 notifyOnOutputEmpty(true)을 설정하여, OUTPUT_BUFFER_EMPTY 기다리고 시도 할 수

class ExampleMonitor implements SerialPortEventListener { 
    boolean condition; 

    public synchronized serialEvent(SerialPortEvent ev) { 
    condition = true; 
    notifyAll(); 
    } 

    public synchronized void awaitCondition() throws InterruptedException { 
    while(!condition) wait(); 
    condition = false; 
    } 

의 라인을 따라 당신의 SerialPortEventListener 모니터를 제작하고 할

myExampleMonitor.awaitCondition() 전송 스레드에서 sleep 대신.

은 (어떤 모니터도없고 대기가 없다,이 점에 유의 대신, 작업이 리스너/콜백에서 이루어집니다.) 이벤트의 역 사용 http://rxtx.qbang.org/wiki/index.php/Event_based_two_way_Communication를 참조

+0

아차, 내 모니터에 오타가 있었다 예, 지금 편집 됨. 죄송합니다. – drRobertz