Lucrarea 0. Comunicarea pe porturile seriale în java

 

Lucrarea 0. Comunicarea pe porturile seriale în java. 1

1. Obiectivul lucrării 1

2. Noţiuni preliminare. 1

2.1 Instrucţiuni de instalare Java Communication API. 2

3. Listare porturi disponibile. 3

4. Deschiderea unui port serial 4

5. Deschiderea unui port paralel 4

6. Scrierea şi citirea de pe un port 5

6.1 Scriere şi citire în mod sincron. 5

6.2 Scriere şi citire în mod asincron. 7

 

1. Obiectivul lucrării

 

Scopul acestei lucrări este de a prezenta modul de accesare a portului serial şi paralel folosind limbajul de programare Java.  

 

2. Noţiuni preliminare

 

Java 2 Standard Edition nu are suport pentru accesarea porturilor seriale. Suportul pentru accesarea porturilor seriale este oferit de SUN prin intermediul pachetului Java Communication API. Prin intermediul acestui pachet programatorul poate accesa porturile seriale şi paralele într-o manieră independentă de platformă. Pentru a putea accesa porturile seriale şi paralele pachetul Java Communication trebuie instalat ulterior.

 

Arhitectura librării pentru accesarea porturilor seriale şi paralele este prezentată în figura 1.

 

Figura 1. Structura Java Communication API.

 

În cadrul librăriei Communication API sunt definite două clase principale: clasa SerialPort şi clasa ParallelPort. Aceste clase moştenesc clasa CommPort (aceasta este o clasă abstractă) şi definesc cele două tipuri de porturi ce pot fi accesate prin intermediul Communication API.

 

Constructorii claselor SerialPort şi ParallelPort nu sunt publici, astfel încât obţinerea unei instanţe a acestor clase se realizează prin intermediul unor metode statice. Pentru a obţine lista de porturi disponibile se foloseşte metoda statică CommPortIdentifier.getPortIdentifiers(). Metoda returnează o listă de obiecte de tip CommPort ce identifică toate porturile disponibile şi care pot fi deschise. Pentru fiecare obiectele de tip CommPort se poate apela metoda open() pentru a deschide respectivul port. De asemenea obiectul poate fi convertit la tipul SerialPort sau ParallelPort în funcţie de tip de port pe care il reprezintă. Fiecare dintre clasele SerialPort şi ParallelPort conţin metodele necesare pentru a putea seta parametrii specific fiecărui tip de port.

 

2.1 Instrucţiuni de instalare Java Communication API

 Java 2 Standard Edition nu include pachetul Java Communication API necesar pentru lucrul cu porturi seriale. Pentru a avea acces la porturile seriale si a putea trimite şi citi date pe porturile seriale si paralele (standardele RS323 şi IEEE 1284) va trebui să descăcaţi şi să instalaţi pachetul Java Communication API.

 Versiunea curentă a acestei librării este 3.0 dar pentru această versiunea nu se oferă suport pentru sistemul de operare Windows. Pentru a putea lucra din Windows va trebui să instalaţi versiunea anterioară a acestei librării – Java Communication API 2.0.

 

Instrucţiuni de instalare pentru platforma Windows 

  1. Descărcaţi pachetul Java Communication API 2.0
  2. Copiaţi fişierul win32com.dll în directorul <jdk>\jre\bin
  3. Copiaţi pachetul  comm.jar în directorul <jdk>\jre\lib\ext
  4. Copiaţi fişierul javax.comm.properties în directorul <jdk>\jre\lib

 S-a notat cu <jdk> calea către directorul de instalare al J2SE (de exemplu c:\java\jdk.1.5.0).

 

3. Listare porturi disponibile

 

Aplicaţia prezentată în această secţiune exemplifică modul în care se poate utiliza librăria Communication API pentru a afişa la consolă toate porturile seriale şi paralele disponibile pe calculator. După cum s-a precizat deja librăria pune la dispoziţia programatorului metoda statică CommPortIdentifier.getPortIdentifiers() ce returnează un obiect de tip Enumeration ce conţine lista de porturi disponibile.

 

import javax.comm.*;

import java.io.*;

import java.util.*;

 

public class Main {

   

    public static void testComm(){

        System.err.println("Test port.");

        Enumeration portList = CommPortIdentifier.getPortIdentifiers();

 

        while(portList.hasMoreElements()){

            CommPortIdentifier cp = (CommPortIdentifier)portList.nextElement();

            System.err.println("Port name="+cp.getName());

            //System.out.println(portList.nextElement().toString());

        }

    }

   

    /**

     * @param args the command line arguments

     */

    public static void main(String[] args) {

        Main.testComm();

    }

   

}

 

4. Deschiderea unui port serial

 

Această secţiune prezintă modul în care poate fi deschis un port serial pentru a realiza operaţii de scriere şi citire.

 

Paşii necesari pentru a deschide un port serial sunt următorii:

  1. Obţinerea obiectului de tip ComPortIdentifier ce identifică portul dorit.
  2. Conversia obiectului la tipul CommPort şi deshiderea portului prin apelarea metodei open() din cadrul obiectului de tip ComPortIdentifier. Atenţie dacă portul este deja deschis de către o altă aplicaţie atunci metoda open() va eşua şi va returna o excepţie.
  3. Construirea obiectelor de tip flux de intrare şi flux de ieşire pentru a scrire respectiv a citi date folosind metodele getInputStream şi getOutputStream. 

 

package commtest;

import javax.comm.*;

import java.io.*;

 

public class OpenSerialPort {

  static int TIMEOUTSECONDS = 5;

  static int BAUD = 38400;

   

  public static void main(String[] args) throws Exception{

     

    DataInputStream is;

    PrintStream os;

   

    CommPortIdentifier thePort = CommPortIdentifier.getPortIdentifier("COM12");

     

    CommPort communicationPort = thePort.open("Test app", TIMEOUTSECONDS * 1000);

   

    SerialPort serialPort = (SerialPort) communicationPort;

   

    serialPort.setSerialPortParams(BAUD, SerialPort.DATABITS_8,

    SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

    serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);

  

   

    try {

        is = new DataInputStream(serialPort.getInputStream());

    } catch (IOException e) {

        System.err.println("Can't open input stream: write-only");

    }

    os = new PrintStream(serialPort.getOutputStream(), true);

    System.out.println("Ready to do read / write on port "+serialPort.getName());

  }

   

}

 

5. Deschiderea unui port paralel

 

Această secţiune prezintă modul în care poate fi deschis un port serial pentru a realiza operaţii de scriere şi citire.

 

Deschiderea portului paralel pentru scriere şi citire se face în mod similar ca şi in cazul portului serial, doar că obiectul generic de tip CommPort va trebui convertit la tipul ParallePort pentru a avea acces la metodele specifice portului paralel. 

 

package commtest;

import javax.comm.*;

import java.io.*;

 

public class OpenParallelPort {

  static int TIMEOUTSECONDS = 5;

  static int BAUD = 38400;

   

  public static void main(String[] args) throws Exception{

     

    DataInputStream is;

    PrintStream os;

   

    CommPortIdentifier thePort = CommPortIdentifier.getPortIdentifier("LPT1");

    

    CommPort communicationPort = thePort.open("Test app", TIMEOUTSECONDS * 1000);

   

    ParallelPort paralelPort = (ParallelPort) communicationPort;

   

   

    try {

        is = new DataInputStream(serialPort.getInputStream());

    } catch (IOException e) {

        System.err.println("Can't open input stream: write-only");

    }

    os = new PrintStream(serialPort.getOutputStream(), true);

    System.out.println("Ready to do read / write on port "+serialPort.getName());

  }

   

}

 

6. Scrierea şi citirea de pe un port

 

Operaţiile de scriere şi citire a porturilor se pot face în două moduri

 

Pachetul Communication API permite realizarea de operaţii de scriere citire atât în mod sincron cât şi in mod asincron.

 

6.1 Scriere şi citire în mod sincron

 

Comunicarea în mod sincron presupune existenţa unui protocol de comunicaţie intre aplicaţia Java şi dispozitivul extern conectat prin portul serial sau paralel în cadrul căruia se cunoaşte exact ordinea comenzilor şi a răspunsurilor ce sunt schimbate prin intermediul portului deschis. La fiecare comandă transmisă se cunoaşte exact ce răspuns trebuie să sosească de la dispozitivul conectat. După fiecare comandă transmisă aplicaţia aşteaptă răspunsul de la dispozitivul cu care realizează comunicarea.

 

package commtest;

import javax.comm.*;

import java.io.*;

 

public class SincronCommunication {

   

    static int TIMEOUTSECONDS = 5;

    static int BAUD = 38400;

    BufferedReader is;

    PrintStream os;

    SerialPort serialPort;

   

    /** Creates a new instance of SincronCommunication */

    public SincronCommunication(String port) throws Exception{

    

    CommPortIdentifier thePort = CommPortIdentifier.getPortIdentifier(port);

    CommPort communicationPort = thePort.open("Test app", TIMEOUTSECONDS * 1000);

    serialPort = (SerialPort) communicationPort;

   

    serialPort.setSerialPortParams(BAUD, SerialPort.DATABITS_8,

    SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

    serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);

    

    try {

        is = new BufferedReader(new InputStreamReader((serialPort.getInputStream())));

    } catch (IOException e) {

        System.err.println("Can't open input stream: write-only");

    }

    os = new PrintStream(serialPort.getOutputStream(), true);

    System.out.println("Ready to do read / write on port "+serialPort.getName());

    }

   

    public void send(String command){

        os.print(command);

        os.println("\r\n");

    }

   

    public boolean expect(String expected) throws IOException{

        String response = is.readLine();

        return response.indexOf(expected)>=0;

    }

   

    public void commProtocol() throws Exception{

        // Send the reset command

       

        send("MESSAGE 1");

        if(!expect("OK 1"))

            System.err.println("ERROR: Device has not sent back expected response.");

        send("MESSAGE 2" );

        if(!expect("OK 2"))

            System.err.println("ERROR: Device has not sent back expected response.");

       

        try {

            Thread.sleep(5000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        is.close();

        os.close();

    }     

   

     public static void main(String[] args) throws Exception{

         SincronCommunication sc = new SincronCommunication("COM12");

         //start communication protocol

         sc.commProtocol();

     }

}

 

6.2 Scriere şi citire în mod asincron

 

Comunicarea în mod asincron presupune că nu se cunoaşte exact în avans ordinea în care au loc operaţiile de scriere şi de citire. În acest caz aplicaţia va trebui să poată sa fie notificată atunci când apare un eveniment pe portul deshis. Pachetul Communication API oferă posibilitatea comunicaţiei în mod asincron folosind pentru aceasta şablonul de proiectare Observer \ Observable (sau altfel spus modelul orientat pe evenimente). Communication API permite înregistrarea de obiecte de tip Observer (sau Listeners) care sunt notificate în momentul în care un eveniment apare pe portul deschis.

package commtest;

import javax.comm.*;

import java.io.*;

/**

 *

 * @author mihai

 */

public class AsincronCommunicationEvents extends Thread implements SerialPortEventListener {

    static int TIMEOUTSECONDS = 5;

    static int BAUD = 38400;

    BufferedReader is;

    PrintStream os;

    SerialPort serialPort;

    /** Creates a new instance of AsincronCommunicationEvents */

    public AsincronCommunicationEvents(String port) throws Exception {

        CommPortIdentifier thePort = CommPortIdentifier.getPortIdentifier(port);

        CommPort communicationPort = thePort.open("Test app", TIMEOUTSECONDS * 1000);

        serialPort = (SerialPort) communicationPort;

 

        serialPort.setSerialPortParams(BAUD, SerialPort.DATABITS_8,

        SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

        serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);

 

        try {

            is = new BufferedReader(new InputStreamReader((serialPort.getInputStream())));

        } catch (IOException e) {

            System.err.println("Can't open input stream: write-only");

        }

        os = new PrintStream(serialPort.getOutputStream(), true);

        System.out.println("Ready to do read / write on port "+serialPort.getName());

        serialPort.notifyOnDataAvailable(true);

        serialPort.addEventListener(this);

    }

   

  public void serialEvent(SerialPortEvent event) {

     System.err.println("New event arrived.");

        switch(event.getEventType()) {

        case SerialPortEvent.BI:

        case SerialPortEvent.OE:

        case SerialPortEvent.FE:

        case SerialPortEvent.PE:

        case SerialPortEvent.CD:

        case SerialPortEvent.CTS:

        case SerialPortEvent.DSR:

        case SerialPortEvent.RI:

        case SerialPortEvent.OUTPUT_BUFFER_EMPTY:

            break;

        case SerialPortEvent.DATA_AVAILABLE:

            try {

                String response = is.readLine();

                System.err.println("Response received:"+response);

            } catch (IOException e) {}

            break;

        }

    }

 

  public void run(){

        try {

        //just wait for 20 seconds

            Thread.sleep(20000);

        } catch (InterruptedException ex) {ex.printStackTrace();}

  }

   public static void main(String[] args) throws Exception{

         AsincronCommunicationEvents sc = new AsincronCommunicationEvents("COM12");

         //start communication protocol

         sc.start();

   }  

}