A Utilização de Portas de Comunicação através de Java
Vicente Peruffo Minotto
Universidade do Vale do Rio dos Sinos
[email protected]
Resumo
sobre a API usada na comunicação de portas; a seção 4
mostra o funcionamento dessa API através de exemplos
de códigos fontes; a seção 5 ilustra o funcionamento de
um programa que utiliza comunicação através da porta
serial; e, por fim, a seção 6 conclui o artigo.
Este artigo discute a utilização de portas de
comunicação de um computador comum através da
linguagem de programação Java. Será analisado por que
os desenvolvedores da Sun implementaram a utilização
da porta serial, e da porta paralela, e por que ainda não
existe suporte para USB, Firewire, ISDN e entre outros
protocolos de comunicação a este nível. Também será
mostrado exemplos de programas, através dos seus
códigos fontes, utilizando API de comunicações do Java
na comunicação com porta serial.
2. Portas de comunicação em geral
Resumidamente, o funcionamento de um porta de
comunicação é baseado na troca de bits entre dois
dispositivos. O modo como os bits são enviados e
recebidos, varia de padrão para padrão, mas o princípio,
em geral é esse [3]. Este artigo não entrará em detalhes
mais aprofundados em relação ao funcionamento de
quaisquer portas.
Todavia, há algumas confusões causadas normalmente
em torno das portas de comunicação. Um exemplo é o de
confundirem-nas com rede. Uma rede opera sobre um
conceito diferente; nela é realizada “conversa” apenas
entre dispositivos que possuem um endereço de IP fixo,
os quais geralmente são computadores, mas podem variar
para celulares, handhelds, etc. Em portas de comunicação,
a “conversa” pode ser realizada com qualquer dispositivo,
como por exemplo, outro computador, mouse, teclado,
motores, CIs, pen drives, etc.
Também, usar Java para redes, é algo completamente
diferente do que usar portas de comunicação. Em redes é
necessário usar classes como Sockets, RMI, Threads
(obrigatoriamente), entre outros. Em portas de
comunicação, é necessário apenas o uso de poucas classes
pertencentes à API específica daquelas portas. Em suma,
portas de comunicação são diferentes de redes. Redes são
mais complexas, e utilizam de um conceito mais
avançado em Java.
1. Introdução
O uso de portas de comunicação está presente no diaa-dia de qualquer um que use o computador; no momento
em que usamos o mouse, o teclado, impressora, pen
drives, entre outros, estamos usando algum tipo de porta
de comunicação. Tudo começou em 1970 quando a
primeira impressora utilizou uma porta paralela para se
conectar a um computador, a Centronic Model 101 [1]. A
partir daí, grandes empresas começaram a lançar
computadores com portas paralelas já integradas. Mas foi
em 1981 que a porta paralela, conhecida como SPP
(Standard Parallel Port) na época, teve seu auge, quando
a IBM lançou o Computador Pessoal (PC).
A partir daí, seguindo uma linha de evolução, foram
surgindo novas portas de comunicação, mais rápidas,
simplificadas e podendo executar mais funções, como: o
padrão RS-232 para portas seriais, o qual teve seu auge
em 1990; em 1995 a Intel introduziu a porta USB, a qual
ficou famosa e começou a ser usada em larga escala
aproximadamente na metade de 1997; o padrão Firewire
(ou IEEE 1394), que, criado pela Macintosh e IBM em
1995, que é muito usado para captura de som, vídeo,
imagens, e outros [2].
Neste cenário, à medida que novos padrões para portas
de comunicação surgiam, as linguagens de programação
precisavam criar um suporte (bibliotecas, APIs, etc) para
estas portas, precisavam acompanhar esta evolução. E
assim foi com a maioria delas, pois grande parte das
linguagens de programação tem suporte para maioria das
portas. O enfoque deste artigo é na relação que Java tem
com estas portas. Quais ela suporta, quais ela não suporta,
se todas APIs são oficiais da Sun ou não, como elas
funcionam, etc.
Deste modo, o artigo está organizado da seguinte
maneira: a seção 2 apresenta uma visão geral das portas
de comunicação; na seção 3 é feita uma breve explicação
3. Java Communication API
A Java Communication API (javax.comm) mais
conhecida como Java Comm, a qual foi criada em 1997 e
pode ser encontrada no link da referência [4], é a API
oficial da Sun usada para comunicação com portas do
padrão RS-232 (portas seriais), e portas paralelas no
modo SPP (a extensão da porta paralela não está
totalmente completa, pois ainda está em desenvolvimento
[5]). Segundo a Sun, a parte de portas seriais está
desenvolvida ao máximo possível, a API fornece tudo que
é necessário para sua utilização da maneira mais
simplificada possível [6].
Eis algumas características da Java Comm [5]:
•
Enumeração de portas (mapeamento das portas);
1
•
•
•
•
Configuração de portas (baud rate, stop bits,
paridade);
Acesso ao padrão EIA232;
Opções de controle de fluxo para hardware e
software;
Opção assíncrona de eventos para notificação de:
o
Data disponível na porta RS-232;
o
Mudança de portas no hardware;
o
Mudança de titularidade em alguma porta
dentro de uma única JVM.
int i = 0;
portas = new String[10];
//...
while (listaDePortas.hasMoreElements()) {
CommPortIdentifier tempPorta =
(CommPortIdentifier)listaDePortas.nextElement();
portas[i] = tempPorta.getName();
i++;
}
//...
O método hasMoreElements() retorna o próximo
elemento da estrutura listaDePortas, mas o loop while
garante que todos os elementos sejam passados ao array
portas através do método getName(). E através de um
simples for, podemos escrever na tela todas as portas
reconhecidas:
Apesar de ainda não existir uma API oficial da Sun
para a utilização de outras portas de comunicação que não
sejam serial e paralela, ela afirma que está investigando a
possibilidade da inserção de outros protocolos de baixo
nível, com USB e Firewire na Java Comm. E também
afirma que não irão dar suporte à protocolos de alto nível
como X/Y/Z-modem, ou Kermit [6, 9]. Em 2003 a Sun
começou um projeto para incluir tais protocolos em uma
API. Eles inicialmente começaram com o javax.usb, para
portas USB; atualmente esta API existe somente para o
sistema operacional Solaris, o qual também é da Sun [7].
Contudo, grupos de terceiros (desenvolvedores que
não são da Sun, assim chamados pela própria Sun) já
fizeram uma API para a comunicação USB para os
sistemas operacionais Windows e Linux. Apesar de
exister mais de uma API para USB, a jUSB (Java USB),
assim chamada pelos seus criadores, é atualmente a mais
famosa e mais usada por aqueles que buscam um caminho
alternativo que não seja o de esperar até a Sun lançar uma
API oficial [8].
for (int j = 0; j < portas.length; j++) {
System.out.println(portas[j]);
}
4.2. Abrindo as portas
O método getPortIdentifier(String porta) da classe
CommPortIdentifier retorna um identificador da porta
escolhida. Note que a string “porta” passada, seria um dos
nomes obtidos das portas que foram reconhecidas e
impressas na tela através do for. É necessário instanciar
um objeto para receber esse identificador:
CommPortIdentifier cpi =
CommPortIdentifier.getPortIdentifier(portaEscolhida);
4. Utilizando a javax.comm
Em seguida deve-se criar uma instância da classe
SerialPort utilizando o identificador obtido. Note que
uma conversão deverá ser feita. A porta só pode ser
instanciada através de um casting, e ao mesmo tempo será
aberta a porta para comunicação:
Muitos programas podem ser desenvolvidos com o
auxílio da javax.comm, pois como dito antes, ela dá
suporte à tudo que uma porta serial necessita. Mas quando
se usa a javax.comm, é necessário partir de um princípio
básico que qualquer programa necessitará: reconhecer as
portas disponíveis no computador, abrir as portas
desejadas, enviar bytes, receber bytes, e verificar se
algum byte realmente foi lido.
SerialPort porta = (SerialPort)cpi.open("SComm",timeout);
O método open() tem como parâmetros o nome da
classe principal onde o código está sendo escrito (isso é
aconselhável para não gerar conflitos com outros
usuários/programas que estejam já usando, ou que forem
tentar usar a porta escolhida anteriormente), e o valor
desejado para timeout (tempo em milissegundos antes de
a porta ser aberta, após a execução do código). Este
método, além de abrir a porta escolhida, retorna um
objeto do tipo CommPort, que através do casting torna-se
um objeto do tipo SerialPort. O fato de o método open()
retornar um objeto do tipo CommPort é porque pode-se
obter um objeto do tipo ParallelPort através de um
casting também, visto que ParallelPort e SerialPort
herdam de CommPort.
4.1. Reconhecendo as portas
A API de comunicação fornece o método
getPortIdentifiers()
integrante
da
classe
CommPortIdentifier que retorna, em uma estrutura
Enumeration, as portas disponíveis. A classe
CommPortIdentifier pode ser instanciada e representar
uma porta. Para isso, precisa-se varrer a estrutura
retornada por getPortIdentifiers() e instanciando cada
porta através de uma conversão (casting) simples:
//...
Enumeration listaDePortas;
listaDePortas = CommPortIdentifier.getPortIdentifiers();
//...
2
4.3. Enviando bytes para a porta serial
porta serial que podem existir dados à serem lidos, através
do método notifyOnDataAvailable().
A classe SerialPort implementa as classes abstratas
InputStream e OutputStream, o que torna o problema
mais simples. Para realizar o envio de dados, basta
instanciar a uma variável do tipo OutputStream a stream
da porta serial, a qual pode ser obtida através do método
getOutputStream().
porta.addEventListener(this);
porta.notifyOnDataAvailable(true);
Agora o evento precisa ser tratado. Primeiro instanciase um array de bytes. Esse array será o buffer de dados.
OutputStream saida = porta.getOutputStream();
public void serialEvent(SerialPortEvent ev){
switch (ev.getEventType()) {
//…
case SerialPortEvent.DATA_AVAILABLE:
byte[] bufferLeitura = new byte[20];
//...
Em seguida é preciso configurar os parâmetros de
comunicação serial, para isso utiliza-se o método
setSerialPortParams().
porta.setSerialPortParams(baudrate, porta.DATABITS_8,
porta.STOPBITS_2, porta.PARITY_NONE);
O método getEventType() da classe SerialPortEvent,
retorna um inteiro, o qual é usado em um switch. Este
inteiro representará o tipo do evento. Dependendo de qual
inteiro foi retornado, o qual vai depender do dado que está
sendo lido, o switch cairá em algum case. Os cases são
variáveis do tipo inteiro e constantes que já são
predefinidas na API e representam os tipos de eventos
possíveis.
Com o fluxo de entrada de dados já definido basta usar
o método available(), que retorna sempre 0 se
InputStream (nesse caso entrada) é classe da qual ele é
invocado.
Estes parâmetros passados são variáveis já
predefinidas na API. Exceto pelo baudrate, que deve ser
escolhido pelo usuário.
Para escrever os dados na porta serial basta escolher os
bytes que se deseja enviar, usar o método write(), e logo
após, o método flush() da classe OutputStream.
String msg = “Olá Mundo!”;
saida.write(msg.getBytes());
saida.flush();
//...
Como a classe OutputStream suporta escrever apenas
bytes, e se o usuário quer escrever uma string como no
exemplo acima, basta usar o método getBytes() que
qualquer tipo de variável tem, ou seja, o mesmo valeria
para enviar chars, ints, doubles, etc.
int nodebyte;
while ( entrada.available() > 0 ) {
nodeBytes = entrada.read(bufferLeitura);
}
//…
4.4 Recebendo bytes na porta serial
O método read(), faz 3 operações ao mesmo tempo.
Ele lê os dados de entrada, escreve eles no array de bytes
passados como parâmetro, e retorna um valor inteiro do
número de bytes que foram lidos. Os bytes lidos e
armazenados na variável bufferLeitura podem agora
serem convertidos para uma String através de um
construtor que a classe String possui.
Apesar de a Java Comm facilitar bastante o trabalho,
receber bytes na porta serial é mais complicado do que
enviar; são várias linhas de código. Os passos que devem
ser seguidos para realizar a leitura de dados são os
seguintes:
•
Criar um fluxo de entrada;
•
Adicionar um gerenciador de eventos para dados
na porta serial;
•
Instanciar uma thread para aguardar os eventos;
•
Tratar o evento e receber os dados.
Primeiramente é preciso criar uma instancia para a
stream de entrada (fluxo de entrada) da porta serial, da
mesma maneira que foi feito para a stream de saída.
//…
String dadosLidos = new String(bufferLeitura);
//…
4.5. Verificando se algum byte foi realmente
lido
Para finalizar, agora é possível verificar se os bytes
foram realmente lidos ou não. Se a dimensão do buffer for
igual zero, isso significa que nenhum byte foi lido. Se a
dimensão do buffer for igual a 1, apenas um byte foi lido.
Caso contrário, a estrutura bufferLeitura recebe os bytes
lidos. O primerio byte lido é armazenado em
InputStream entrada = porta.getInputStream();
Após a criação do fluxo de entrada, é preciso adicionar
um gerenciador de eventos para a porta serial. Isso é
possível através do método addEventListener() que a
classe SerialPort possui. Em seguida basta notificar a
3
bufferLeitura[0], o segundo em bufferLeitura[1] e assim
por diante.
configurada para ler bytes de entrada, ou seja, para
receber um SMS; e para escrever a mensagem desejada,
basta digita-la no campo cinza superior, e pressionar
enter.
//...
if (bufferLeitura.length == 0) {
System.out.println("Nada lido!");
} else if (bufferLeitura.length == 1 ){
System.out.println("Apenas um byte foi lido!");
} else {
System.out.println(dadosLidos);
}
System.out.println("n.o de bytes lidos : " + nodeBytes );
break;
6. Conclusão
Apesar das lacunas que a Java Comm apresenta, é
seguro afirmar que ela simplifica bastante o uso da porta
serial. Como mostrado nos códigos fontes, o básico a ser
feito quando desenvolvendo um programa que necessite
de comunicação serial, é algo de simples imlementação
para um programador que já tenha alguma base em Java.
Com um programa feito em Java, é possível realizar a
mesma função que qualquer outro programa desenvolvido
em outras linguagens; na maioria das vezes, com soluções
até mais simples e práticas, pelo fato de Java ser uma
linguagem Orientada a Objetos, e possuir um grande
suporte da comunidade de desenvolvedores.
Entretanto, enquanto a Sun não desenvolve uma API
oficial para outros protocolos de comunicação, na maioria
das vezes, existirá APIs de terceiros que, na maior parte
dos casos, são muito eficientes, e sufucientes para a
resolução de muitos problemas.
Note que o case SerialPortEvent.DATA_AVAILABLE
só termina agora. Todas as linhas de códigos apresentadas
após ele terminam no break acima. Se o usuário desejasse
tratar algum outro evento, seria necessário mais cases.
5. Exemplo de um programa desenvolvido
usando a javax.comm
A diversidade de programas, que necessitam
comunicação de porta serial, e que podem ser
implementados utilizando a Java Comm é inacabável,
como por exemplo, um simples software que envia e/ou
recebe SMSs (Short Message Service) para/de um celular.
Este software, o Serial SMS, assim chamado e
desenvolvido por Stefan Moscibroda em 2001, está
listado nas referências [9].
7. Referências
[1]Guia do Hardware - a evolução das portas de comunicação.
http://www.guiadohardware.net/artigos/evolucao-portas/, Junho
de 2008.
[2]Ackadia - Serial & parallel ports. UART, USB, Firewire &
FC-AL
http://www.ackadia.com/computer/system-architecture/systemarchitecture-comms.php, Junho de 2008.
[3]Rogercom – Controle de acesso da porta serial.
http://www.rogercom.com/PortaSerial/ControleAcesso/Controle
.htm, Junho de 2008.
[4]Sun - Java Communication API (javax.comm)
http://java.sun.com/products/javacomm/reference/api/index.htm,
Junho de 2008.
[5]Sun – Java communication API features.
http://java.sun.com/products/javacomm/, Junho de 2008.
[6]Sun – Java communication API FAQ.
http://java.sun.com/products/javacomm/reference/faqs/index.ht
ml, Junho de 2008.
[7]Sun – Java USB communication for Solaris.
http://developers.sun.com/solaris/developer/support/driver/wps/
usb/usb.pdf, Junho de 2008.
[8]Sourceforge – Java third party USB API.
http://jusb.sourceforge.net/, Junho de 2008.
[9]Stefan Moscibroda – Serial SMS
http://ufpr.dl.sourceforge.net/sourceforge/serialsmsclient/Serial_
SMS.zip, Junho de 2008.
Fig. 1. – Programa Serial SMS em execução.
A Fig. 1 mostra o programa em execução. A sua
implementação é basicamente: uma interface gráfica
desenvolvida usando as Interfaces AWT e Swing, na qual
é possível configurar as características principais da porta
serial, como mostrado na figura; e uma lógica de envio e
recebimento das mensagens SMS. No momento que o
usuário clica no botão open port, a porta escolhida é
4
Download

Vicente - Unisinos