Lucrarea 0. Comunicarea pe porturile seriale în java
2.1 Instrucţiuni de instalare Java Communication API
3. Listare porturi disponibile
4. Deschiderea unui port serial
5. Deschiderea unui port paralel
6. Scrierea şi citirea de pe un port
6.1 Scriere şi citire în mod sincron
6.2 Scriere şi citire în mod asincron
Scopul acestei lucrări este de a prezenta modul de accesare a
portului serial şi paralel folosind limbajul de programare Java.
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.
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
S-a notat cu <jdk> calea către directorul de instalare al J2SE (de exemplu c:\java\jdk.1.5.0).
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();
}
}
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:
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());
}
}
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());
}
}
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.
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();
}
}
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();
}
}