IT_Programming/Java

[펌] Java 직렬통신

JJun ™ 2009. 8. 24. 11:43

출처 : http://novaws.egloos.com/609241 | http://mean79.tistory.com/100

 

 

[ Java에서 Serial(RS-232)통신 준비 ]

 

Java에서 RS-232c나 패러럴(parallel)포트에 접근하기 위해서는 Communication API을 사용해야

합니다. Communication API은 자바 J2SE에서 제공하는 표준 API가 아니므로, 추가적으로 다운로드 받아서 설치 해주셔야 합니다. 참고로, 자바의 Communication API 공식 사이트 주소는 다음과 같습니다. http://java.sun.com/products/javacomm/index.html


1. Communication Download
    
http://java.sun.com/products/javacomm/downloads/index.html

    접속하여 해당 OS별 API을 다운로드 받습니다.

    윈도우즈의 경우, (javacomm20-win32.zip) 입니다.


2. 압축 해제 후
    comm.jar                      → C:\JDK 경로\jre\lib\ext
    javax.comm.properties  C:\JDK 경로\jre\lib
                                             C:\JRE 경로\lib
    win32com.dll                 C:\JDK 경로\bin
                                         C:\JDK 경로\JRE\bin
    각 경로에 파일 Copy


3. comm.jar을 클래스 패스에 추가 시켜 줍니다. 

   : 이 방식 보다는 아래의 포스트의 방식으로 사용하자!
 

 


4. 프로그램 작성
    Communication API을 사용하려는 클래스에서  javax.comm 팩키지를 import해주면 됩니다.

 

 

-------------------------------------------------------------------------------------------------

 

설정이 끝나면 Java Communications API 클래스는 javax.comm 패키지로 사용 가능하다.

이 패키지에서 핵심이 되는 클래스는 CommPortIdentifier와 CommPort이다.

CommPortIdentifier는 설치된 CommPort 객체를 찾는 데 사용된다.

그리고 각각의 CommPort 객체와 통신할 수 있다.


// Rs232c.java

import java.io.*;
import javax.comm.*;
public class Rs232c {
    public static void main( String arg[] ) {
        try {
            CommPortIdentifier ports = CommPortIdentifier.getPortIdentifier( "COM1" );
            SerialPort port = ( SerialPort )ports.open( "RS232C", 1000 );
            port.setSerialPortParams( 9600,
                SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE );
            port.setFlowControlMode( SerialPort.FLOWCONTROL_NONE );
            OutputStream out = port.getOutputStream();
            String msg = "Hello";
            out.write( msg.getBytes() );
            out.flush();
            out.close();
            port.close();
        }
        catch( Exception e ) {
            System.out.println( "Error:" + e.getMessage() );
        }
    }
}



Java Communications(COMM) API는 Java 2 플랫폼의 옵션 패키지이다.
이는 컴퓨터 주변기기와 직렬, 병렬 포트를 이용해서 통신할 수 있는 기능을 제공한다.
이 API는 여러 플랫폼에서 잘 정의되었으므로, 특정 플랫폼에 맞게 COMM라이브러리를 다운받아서 사용해야 한다. 이 팁은 COMM API를 이용해서 사용가능한 포트 목록을 얻어오는 방법과 프린터로

출력하는 방법을 예제로 보여준다.

 

COMM API에서는 Universal Serial Bus (USB)는 지원하지 않는다.
USB 지원방안은 Java Community Process (JCP)에서 진행중이다.

더 많은 정보는 JSR 80에서 확인하자. 먼저 Java Communications API를 다운로드하고 압축을 푼다.
다운로드는 Java Communications API page 에서 원도우용이나 솔라리스용을 받을 수 있다.

다운로드한 후에 약간의 설정 작업이 필요하다. comm.jar를 클래스패스에 포함하지 말고,

공유라이브러리 파일을 bin 디렉터리로 복사하고 javax.comm.properties 파일을 런타임 환경의 lib으로 복사하자. 윈도우 Java 2 SDK 버전 1.3에서 다음과 같다.

copy comm.jar \jdk1.3\jre\lib\ext
copy win32com.dll \jdk1.3\bin
copy javax.comm.properties \jdk1.3\jre\lib

설정이 끝나면 Java Communications API 클래스는 javax.comm 패키지로 사용 가능하다.
이 패키지에서 핵심이 되는 클래스는 CommPortIdentifier와 CommPort이다.

CommPortIdentifier는 설치된 CommPort 객체를 찾는 데 사용된다.
그리고 각각의 CommPort 객체와 통신할 수 있다. 어떤 포트가 설치되었는지 찾으려면,

CommPortIdentifier에게 getPortIdentifiers()와 더불어 설치된 집합을 요구한다.
이는 CommPortIdentifier 객체의 Enumeration을 반환한다. 각 객체는 PORT_PARALLEL나 PORT_SERIAL 타입이고, 이 둘은 CommPortIdentifier 클래스에서 일정하다.

다음 코드는 사용가능한 포트의 이름과 타입을 가져오는 예제이다.

import javax.comm.*;
import java.util.Enumeration;

public class ListPorts
{
  public static void main(String args[]) {
    Enumeration ports = CommPortIdentifier.getPortIdentifiers(); 

    while (ports.hasMoreElements()) {
      CommPortIdentifier port = (CommPortIdentifier)ports.nextElement();
      String type;
      switch (port.getPortType()) {
        case CommPortIdentifier.PORT_PARALLEL:
          type = "Parallel";
          break;
        case CommPortIdentifier.PORT_SERIAL:
          type = "Serial";
          break;
        default: /// Shouldn't happen
          type = "Unknown";
          break;
      }
      System.out.println(port.getName() + ": " + type);
    }
  }
}


ListPorts는 다음과 비슷한 결과를 출력한다.
COM1: Serial
COM2: Serial
LPT1: Parallel
LPT2: Parallel


또한, CommPortIdentifier에서 포트 Enumeration을 돌면서 포트의 정보를 얻어 올 수도 있다. getPortIdentifier() 메소드에 포트의 이름을 인수로 전달해서(예 LPT1) 이 작업을 할 수 있다.

반환되는 값은 포트 식별자이고, 포트가 존재하지 않으면 javax.comm.NoSuchPortException으로

예외처리 한다.


// Get port
CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(portname);

포트를 읽거나 쓰기 위해서 open() 메소드를 사용해야 한다.

open() 메소드는 포트 소유자 이름과 밀리세컨드 단위로 타임아웃 시간이 필요하다.


// Open port
// Open requires a owner name and timeout
CommPort port = portId.open("Application Name", 30000);


포트를 열면 소켓통신과 같이 읽기/쓰기가 가능하다. CommPort의 getInputStream() 메소드로 InputStream을 사용하고, getOutputStream()를 통해서 OutputStream을 얻을 수 있다.

// Setup output
OutputStream os = port.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);

이제 COMM API를 이용해서 파일을 출력해 보자. 일단 프린터 포트를 찾고,
그것을 열어서 OutputStream을 얻어온 후 파일내용을 보내면 된다.

다음 예제는 그 과정을 보여준다. sample.ps라는 PostScript 파일을 출력한다.
sample.ps을 먼저 만들고, 작업이 끝난 후에는 포트와 스트림을 닫아 준다.

import javax.comm.*;
import java.io.*;

public class PrintFile {
  public static void main(String args[])
      throws Exception {
    if (args.length != 2) {
      System.err.println("usage : java PrintFile port file");
      System.err.println("sample: java PrintFile LPT1 sample.ps");
      System.exit(-1);
    } 

    String portname = args[0];
    String filename = args[1]; 

    // Get port
    CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(portname); 

    // Open port
    // Open requires a owner name and timeout
    CommPort port = portId.open("Application Name", 30000); 

    // Setup reading from file
    FileReader fr = new FileReader(filename);
    BufferedReader br = new BufferedReader(fr); 

    // Setup output
    OutputStream os = port.getOutputStream();
    BufferedOutputStream bos = new BufferedOutputStream(os); 

    int c;
    while ((c = br.read()) != -1) {
      bos.write(c);
    } 
    // Close
    bos.close();
    br.close();
    port.close();
  }
}


 


import java.io.*;
import java.util.*;
import javax.comm.*;

public class SerialEcho implements Runnable, SerialPortEventListener {
   static CommPortIdentifier portId;
   static Enumeration portList;

   BufferedReader br;
   BufferedWriter bw;
   String echoMsg;
   SerialPort serialPort;
   Thread readThread;

 public static void main(String[] args) {

     // 시스템의 모든 포트 리스트를 가져옴.

  portList = CommPortIdentifier.getPortIdentifiers();

  while (portList.hasMoreElements()) {
   portId = (CommPortIdentifier) portList.nextElement();

   // 현재 포트타입이 시리얼 포트일 경우

   if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {

     // MS-windows에서 시리얼 포트 이름은 “COM1”,”COM2”…
    if (portId.getName().equals("COM1")) {
     // if (portId.getName().equals("/dev/term/a")) { a Solaris에서
       // 시리얼 통신을 위한 포트 생성
     SerialEcho reader = new SerialEcho();
    }
   }
  }
 }

 public SerialEcho() {
     try{
         serialPort = (SerialPort) portId.open("SerialEcho", 2000);
        }  catch (PortInUseException e) {}

     try {
         br = new BufferedReader(new InputStreamReader(serialPort.getInputStream()));
            bw = new BufferedWriter(new OutputStreamWriter(serialPort.getOutputStream()));
        }  catch (IOException e) {}
        try {
          // 시리얼 포트에 데이터가 수신되기를 기다림.
         serialPort.addEventListener(this);
        } catch (TooManyListenersException e) {}
       // input data가 들어오면 수신 통보
        serialPort.notifyOnDataAvailable(true);
    try{
            serialPort.setSerialPortParams(19200,        // Baud Rate
            SerialPort.DATABITS_8,                               // Data Bits
            SerialPort.STOPBITS_1,                              // Stop Bits
            SerialPort.PARITY_NONE);                          // Parity
        }  catch (UnsupportedCommOperationException e) {}
         readThread = new Thread(this);
            readThread.start();
  }
 public void run() {
  try {
   Thread.sleep(20000);
  }  catch (InterruptedException e) {}
 }
 
 public void serialEvent(SerialPortEvent event) {
        switch(event.getEventType()) {
          case SerialPortEvent.BI:      // Break interrupt
          case SerialPortEvent.OE:     // Overrun error
          case SerialPortEvent.FE:      // Framing error
          case SerialPortEvent.PE:     // Parity error.
    case SerialPortEvent.CD:     // Carrier detect
    case SerialPortEvent.CTS:   // Clear to send
    case SerialPortEvent.DSR:   // Data set ready
    case SerialPortEvent.RI:      // Ring indicator.
    case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
      break;             // Output buffer is empty
// Data available at the serial port.
          case SerialPortEvent.DATA_AVAILABLE: