Está en la página 1de 5

Programacin de dispositivos Bluetooth a travs de Java

Alberto Gimeno Brieba


gimenete@gimenete.net

(OBject Exchange); se trata de un protocolo de alto nivel


Abstract muy similar a HTTP.
En este documento se trata la programacin de dispositivos
Bluetooth con Java mediante el API desarrollada por el JCP 3 El paquete javax.bluetooth
y especificada en el JSR-82.
Primero abordaremos la programacin de un cliente y
Keywords: Java, Bluetooth, J2ME, JSR-82, mviles. ms tarde veremos cmo programar un servidor.

3.1 Clientes Bluetooth


1 Introduccin
Un cliente Bluetooth deber realizar las siguientes
Bluetooth es una tecnologa de comunicacin operaciones para comunicarse con un servidor
inalmbrica, al igual que la tecnologa Wi-Fi o los Bluetooth:
infrarrojos. A diferencia de la primera, Bluetooth est
diseada para dispositivos de bajo consumo y para Bsqueda de dispositivos
conexiones de corta distancia (10 metros). A diferencia Bsqueda de servicios
de los infrarrojos, Bluetooth es omnidireccional y tiene
un mayor ancho de banda (hasta 11 Mbit/ segundo). Establecimiento de la conexin

Bluetooth es, pues, una tecnologa ideal para la conexin Comunicacin


de dispositivos de bajas prestaciones (mviles, cmaras El punto de partida es la clase LocalDevice que
de fotos, auriculares manos libres, impresoras,). representa el dispositivo en el que se est ejecutando la
Uno de los mayores mbitos de utilizacin de Bluetooth aplicacin. Este objeto es un singleton y se obtiene
es sin duda los telfonos mviles. Cada vez es ms mediante LocalDevice.getLocalDevice(). Este objeto
comn encontrar terminales mviles con soporte para permite obtener informacin sobre el dispositivo: modo
Java y Bluetooth y simplemente es un paso natural que de conectividad, direccin bluetooth y nombre del
surja la necesidad de programar estos dispositivos a dispositivo.
travs de Java. Desde el JCP se ha desarrollado un JSR El primer paso que debe realizar un cliente es realizar
que cubre esta necesidad. Se trata del JSR-82 que ser una bsqueda de dispositivos. Para ello deberemos
explicado en este documento. obtener un objeto DiscoveryAgent. Este objeto es nico y
se obtiene a travs del objeto LocalDevice.
2 El JSR-82
DiscoveryAgent da =
El JSR-82[1] especifica un API de alto nivel para la LocalDevice.getLocalDevice().getDiscoveryAgent();
programacin de dispositivos Bluetooth. Depende de la
El objeto DiscoveryAgent nos va a permitir realizar y
configuracin CLDC de J2ME, y se divide en dos
cancelar bsquedas de dispositivos y de servicios. Y
paquetes: javax.bluetooth y javax.obex. El primer
tambin nos servir para obtener listas de dispositivos ya
paquete provee la funcionalidad para la realizacin de
conocidos. Esto se lleva a cabo llamando al mtodo
bsquedas de dispositivos, bsquedas de servicios y
retrieveDevices(). A este mtodo se le debe pasar un
comunicacin mediante flujos de datos (streams) o
argumento de tipo entero que puede ser:
arrays de bytes. Por otro lado el paquete javax.obex
permite la comunicacin mediante el protocolo OBEX
DiscoveryAgent.PREKNOWN. Para obtener una DiscoveryListener.INQUIRY_COMPLETED si la
lista de dispositivos encontrados en bsquedas bsqueda concluy con normalidad,
anteriores.
DiscoveryListener.INQUIRY_TERMINATED si la
DiscoveryAgent.CACHED. Para obtener una lista bsqueda ha sido cancelada manualmente o
de dispositivos favoritos.
DiscoveryListener.INQUIRY_ERROR si se produjo
El mtodo retrieveDevices() devuelve un array de objetos un error en el proceso de bsqueda.
RemoteDevice. La clase RemoteDevice representa un
Ya hemos conseguido dar el primer paso para realizar
dispositivo remoto y tiene mtodos similares a
una conexin cliente. El siguiente paso es realizar una
LocalDevice que, recordemos, representa al dispositivo
bsqueda de servicios. Antes de seguir deberemos
en el que se ejecuta la aplicacin. As pues, podemos
comprender ciertos conceptos.
obtener el nombre del dispositivo mediante
getFriendlyName() y su direccin bluetooth mediante Una aplicacin cliente es una aplicacin que requiere un
getBluetoothAddress(). servidor para que le ofrezca un servicio. Este servicio
puede ser: un servicio de impresin, un servicio de
Podramos omitir la bsqueda de dispositivos y pasar
videoconferencia, un servicio de transferencia de
directamente a la bsqueda de servicios en caso de que
archivos, etc. En una comunicacin TCP-IP un cliente se
desesemos conectar con alguno de los dispositivos
conecta directamente a un servidor del que conoce el
pertenecientes a alguna de estas listas. Sin embargo lo
servicio que ofrece, es decir, conocemos a priori la
ms comn ser intentar conectar con un dispositivo
localizacin del servidor y el servicio que nos ofrecer;
encontrado en una bsqueda de dispositivos, debido a
sin embargo un cliente Bluetooth no conoce de
que obviamente lo tendremos a nuestro alcance.
antemano qu dispositivos tiene a su alcance ni cules
Una bsqueda de dispositivos se inicia llamando al de ellos pueden ofrecerle el servicio que necesita. De
mtodo startInquiry(). Este mtodo requiere un modo que un cliente Bluetooth necesita primero buscar
argumento de tipo DiscoveryListener. DiscoveryListener los dispositivos que tiene a su alcance y posteriormente
es una interfaz que implementaremos a nuestra les preguntar si ofrecen el servicio en el que est
conveniencia y que ser usada para que el dispositivo interesado. Este ltimo proceso se denomina bsqueda
notifique eventos a la aplicacin cada vez que se de servicios y es el siguiente paso que un cliente debe
descubre un dispositivo, un servicio, o se finaliza una realizar.
bsqueda. Estos son los cuatro mtodos de la interfaz
Cada servicio es identificado numricamente. Es decir, a
DiscoveryListener:
cada servicio le asignamos un nmero y para referirnos
deviceDiscovered() a dicho servicio usaremos su nmero asociado. Este
identificador se denomina UUID (Universal Unique
inquiryCompleted()
IDentifier). Adicionalmente, cada servicio tiene ciertos
servicesDiscovered() atributos que lo describen. Por ejemplo un servicio de
impresin podra describirse por diversos atributos
serviceSearchCompleted()
como: tipo de papel (dinA4, US-letter,), tipo de tinta
Los dos primeros mtodos son llamados en el proceso (color, blanco y negro), etc. Los atributos tambin estn
de bsqueda de dispositivos. Los otros dos son llamados identificados numricamente, es decir, para referirnos a
en procesos de bsqueda de servicios. un atributo usaremos su nmero asociado.

Cada vez que un dispositivo es encontrado se llama al Las bsquedas de dispositivos tambin se realizan
mtodo deviceDiscovered() pasando un argumento de mediante el objeto DiscoveryAgent. Concretamente
tipo RemoteDevice. usaremos el mtodo searchServices() al que le
tendremos que pasar un objeto DiscoveryListener que
Una vez que la bsqueda de dispositivos ha concluido se
recibir los eventos de la bsqueda, el dispositivo en el
llama al mtodo inquiryCompleted() pasando como
que realizar la bsqueda (un objeto RemoteDevice que
argumento un entero que indica el motivo de la
normalmente obtendremos en la bsqueda de
finalizacin. Este entero puede valer:
dispositivos), los servicios en los que estamos
interesados, y los atributos que queremos conocer sobre
dichos servicios (tipo de papel, tipo de tinta, etc). Por open() y le pasaremos una URL que contendr los datos
ejemplo un cliente que est interesado en un servicio de necesarios para realizar la conexin.
impresin, para imprimir un texto probablemente slo le
No necesitaremos construir la URL a mano ya que el
interese conocer el tipo de papel, sin embargo si
objeto ServiceRecord posee un mtodo que nos ahorra
queremos imprimir una imagen estaremos tambin
esta tarea: getConnectionURL().
interesados en si soporta o no tinta de color.
Llegados a este punto debemos saber que tenemos dos
Si se encuentra algn servicio se nos notificar a travs
formas diferentes de comunicacin: a travs de flujos de
del objeto DiscoveryListener mediante el mtodo
datos utilizando el protocolo SPP (Serial Port Profile) , o
servicesDiscovered(). Se nos pasar un array de objetos
bien a travs de L2CAP enviando y recibiendo arrays de
ServiceRecord que encapsulan los atributos de servicio
bytes. La forma ms sencilla es mediante SPP.
que solicitamos al invocar la bsqueda. Los valores de
estos atributos de servicio son objetos DataElement. Si el servidor utiliza SPP el mtodo Connector.open() nos
devolver un objeto de tipo
Un objeto DataElement encapsula los tipos de datos en
javax.microedition.io.StreamConnection. A travs de
los que puede ser representado un atributo de servicio.
este objeto podemos obtener un (Data)InputStream y un
Estos pueden ser: nmeros enteros de diferente longitud
(Data)OutputStream. Por lo tanto ya tenemos un flujo
con o sin signo, cadenas de texto, URLs, booleanos, o
de lectura y un flujo de escritura por lo que estamso en
colecciones de DataElements.
condiciones de leer y escribir datos.
Un ServiceRecord es, pues, como una tabla que
En caso de que el servidor utilice L2CAP el mtodo
relaciona los identificadores de los atributos con sus
Connector.open() nos devolver un objeto del tipo
valores (objetos DataElement).
javax.bluetooth.L2CAPConnection. Con este objeto
Cuando finalice la bsqueda de servicios se nos leeremos bytes con receive() y escribiremos bytes con
notificar mediante una llamada al mtodo send().
serviceSearchCompleted() de la interfaz
DiscoveryListener. Se nos pasar un argumento de tipo
3.2 Servidores Bluetooth
entero indicando el motivo de la finalizacin. Este
entero puede valer: La creacin de un servidor Bluetooth es ms sencilla que
la programacin de un cliente ya que no necesitamos
SERVICE_SEARCH_COMPLETED: la bsqueda ha realizar ningn tipo de bsqueda. Concretamente los
finalizado con normalidad. pasos que debe realizar un servidor Bluetooth son los
SERVICE_SEARCH_TERMINATED: la bsqueda siguientes:
ha sido cancelada manualmente. Crear una conexin servidora
SERVICE_SEARCH_NO_RECORDS: no existe la Especificar los atributos de servicio
informacin solicitada.
Abrir las conexiones cliente
SERVICE_SEARCH_ERROR: finaliz por un error.
Crear la conexin servidora es relativamente simple.
SERVICE_SEARCH_DEVICE_NOT_REACHABLE: el Sencillamente debemos llamar al mtodo
dispositivo no est a nuestro alcance. Connector.open() pasndole una URL con una sintaxis
Estas constantes son miembros de la interfaz determinada. En caso de querer comunicarnos mediante
DiscoveryListener. SPP la URL comenzar por btspp:// y en caso de querer
comunicarnos mediante L2CAP la URL comenzar por
Si hemos encontrado algn servicio que nos interesa btl2cap://. A continuacin deberemos indicar
pasaremos al siguiente paso: abrir la conexin. localhost/ como host. Esto determina que no
Abrir una conexin Bluetooth se lleva a cabo de la queremos conectarnos a nadie, sino que queremos ser
misma forma que se abre cualquier otro tipo de servidores. Seguidamente slo nos queda concatenar a
conexin en CLDC: a travs de la clase la URL el identificador del servicio (UUID) que vamos a
javax.microedition.Connector. Usaremos su mtodo ofrecer.
A continuacin llamaremos al mtodo Connector.open() DISCONNECT. Usado para finalizar la sesin.
pasando la URL como argumento. Si la URL comienza
Las cabeceras de un mensaje OBEX son encapsuladas por
por btspp:// nos devolver un objeto del tipo
un objeto HeaderSet. Existen cabeceras de uso comn
javax.microedition.StreamConnectionNotifier y en caso
como COUNT, NAME, LENGTH, Sin embargo podremos
de que la URL comience por btl2cap:// nos devolver
crear cabeceras personalizadas.
un objeto javax.bluetooth.L2CAPConnectionNotifier.
La clase Operation provee la funcionalidad para leer y
El siguiente paso es especificar los atributos de servicio.
enviar mensajes que no slo tienen cabeceras sino que
Por ejemplo si vamos a ofrecer un hipottico servicio de
tambin tienen un cuerpo de mensaje. Esta clase permite
impresin podramos indicar qu tipo de papel y de tinta
obtener un (Data)InputStream y un (Data)OutputStream
ofrecemos. Los atributos de servicio se almacenan en un
para leer o escribir el cuerpo del mensaje.
objeto ServiceRecord. Cada conexin servidora tiene un
ServiceRecord asociado que se obtiene a travs del Ahora que conocemos las clases bsicas pasemos a ver
LocalDevice. cmo programar un cliente OBEX.

Establecer los atributos de servicio es sencillo,


simplemente tenemos que crear objetos DataElement y 4.1 Un cliente OBEX
aadirlos al ServiceRecord. La programacin de un cliente OBEX es relativamente
Una vez establecidos los atributos de servicio ya estamos simple. Debemos abrir la conexin, como siempre en
en condiciones de escuchar y procesar las conexiones CLDC con el objeto Connector. Deberemos pasarle una
cliente. Para ello usaremos el mtodo acceptAndOpen(). URL que comience por irdaobex:// y nos devolver un
En una conexin servidora SPP este mtodo devuelve un objeto de tipo javax.obex.ClientSession. Lo primero que
javax.microedition.StreamConnection, y en una conexin deberemos hacer ser ejecutar el mtodo connect() para
servidora L2CAP devuelve un objeto del tipo iniciar la sesin.
javax.bluetooth.L2CAPConnection. En este punto ya A partir de aqu ya podemos realizar peticiones al
podemos leer y escribir datos del mismo modo que lo servidor a travs de los mtodos put(), delete(), get() y
hace un cliente. setPath(). Todos los mtodos requieren un objeto
HeaderSet como parmetro. Los mtodos put() y get()
4 El paquete javax.obex adicionalmente devuelven un objeto Operation que
permite escribir o leer el cuerpo del mensaje
El paquete javax.obex permite manejar el protocolo de
respectivamente.
alto nivel OBEX (OBject Exchange). Se trata de un
protocolo muy similar a HTTP. Al igual que este ltimo, Para cerrar la sesin llamaremos al mtodo disconnect().
OBEX se basa en mensajes compuestos por cabeceras de
mensaje y opcionalmente de un cuerpo de mensaje.
4.2 Un servidor OBEX
Adicionalmente los mensajes de respuesta del servidor
poseen un cdigo de respuesta indicando xito o error. Crear una conexin servidora OBEX es tambin muy
simple. Lo primero de todo es crear un SessionNotifier
Al igual que en HTTP, los mensajes de peticin del cliente llamando al mtodo Connector.open(). La URL debe
al servidor en OBEX se clasifican por mtodos. Estos son comenzar por irdaobex://localhost. Ahora simplemente
los mtodos que existen. escucharemos las conexiones cliente llamando al mtodo
CONNECT. Inicia la sesin. acceptAndOpen(). Este mtodo requiere un argumento
de tipo ServerRequestHandler. El ServerRequestHandler
PUT. Enva un archivo al servidor. es un objeto que deberemos implementar nosotros. Se
GET. Solicita un archivo al servidor. implementa de forma muy similar a un servlet: por cada
mtodo del protocolo OBEX tiene un mtodo asociado al
DELETE. Solicita la eliminacin de un archivo. que se le pasan los datos de la peticin. As pues
SETPATH. El cliente desea cambiar el directorio tenemos los mtodos onConnect(), onGet(), onPut(),
actual dentro del sistema de archivos del onDelete() y onDisconnect(). Todos los mtodos tienen
servidor. como argumento un objeto HeaderSet que encapsula las
cabeceras de los mensajes, exceptuando los mtodos
onPut() y onGet() que requieren un cuerpo de mensaje y de carrera. Pero sobre todo a todos los miembros de
por ello su argumento es de tipo Operation. javaHispano por hacer esto posible.

Adicionalmente todos los mtodos a excepcin de


onDisconnect() deben devolver un entero que ser el Referencias
cdigo de respuesta indicando el xito o no de la
[1] Especificacin del JSR-82: Bluetooth desde Java.
peticin y su motivo. http://jcp.org/en/jsr/detail?id=82.
[2] Alberto Gimeno Brieba. JSR-82: Bluetooth desde Java.
http://www.javahispano.org/tutorials.item.action?id=49.
5 Implementaciones del JSR-82
Existen dispositivos mviles que soportan Java y tienen
Bluetooth, pero sin embargo no soportan el API JSR-82.
Esto quiere decir que no tenemos posibilidad de acceder
al dispositivo Bluetooth a travs de Java. Por ello habr
que acudir a las especificaciones del fabricante para
cerciorarnos de que las APIs estn soportadas.

A pesar de que el JSR-82 se especific pensando en la


plataforma J2ME. No slo existen implementaciones y
emuladores para J2ME. Debido a que J2ME es una
versin reducida de J2SE, es perfectamente factible crear
una implementacin que pueda ser usada desde J2SE.
De hecho existen implementaciones y emuladores. La
mayora de estas implementaciones son libres y suelen
soportar dispositivos Bluetooth conectados al puerto
serie. Otras implementaciones son bindings para Java de
las APIs Bluetooth que ofrece el sistema operativo.

Ciertos emuladores y entornos de desarrollo tambin


implementan estas APIs simulando dispositivos
Bluetooth, es decir, permiten realizar aplicaciones que
usen las APIs JSR-82 sin necesidad de tener fsicamente
un dispositivo Bluetooth.

6 Documentacin
La documentacin sobre las APIs definidas en el JSR-82
es muy escasa y mucho ms escasa es en espaol. Sin
embargo en javaHispano se public un tutorial[2] al
respecto en el que se puede encontrar mas informacin y
enlaces a otros documentos.

Por ltimo aadir que siempre es fundamental tener a


mano la documentacin javadoc de las APIs, la cual se
puede descargar desde la pgina del JSR-82[1] junto con
la especificacin.

Agradecimientos
Agradezco su apoyo a la Escuela Universitaira Politcnica
de La Almunia, a ngel Blesa y a todos mis compaeros

También podría gustarte