Il Bluetooth è uno standard per la comunicazione wireless a corto raggio, impiegato per la realizzazione di una Personal Area Network (PAN), ossia di una rete informatica in grado di interconnettere diversi dispositivi (telefoni cellulari, personal digital assistants, laptop, ecc.) vicini a un singolo utente. Scopo di questo articolo è l‘introduzione ai concetti base della tecnologia Bluetooth e della specifica JSR-82 [2], con i quali realizzeremo la prima parte del nostro esempio, ovvero il discovery di un dispositivo Bluetooth.
Introduzione al Bluetooth
Il Bluetooth, noto anche con la sigla IEEE 802.15.1, è uno standard aperto per comunicazione wireless a corto raggio. Sulla base della distanza coperta, i dispositivi Bluetooth vengono classificati in 3 classi, come mostrato nella tabella di figura 1.
Le caratteristiche principali dello standard sono:
Tecnologia radio a bassa potenza e portata limitata nella banda 2.4GHz (ISM);
Supporto per voce e dati con velocità di trasferimento da 723.1 kbit/s per la versione 1.2 fino a 2.1Mbit/s per la versione 2.0;
I dispositivi non devono essere necessariamente in –vistaâ? (come ad esempio nel caso della tecnologia a infrarossi).
Ogni dispositivo Bluetooth è univocamente identificato e indirizzabile mediante un indirizzo IEEE 802 a 48 bit. Quando due o più dispositivi sono connessi fra loro formano una rete PAN, denominata Piconet, alla quale possono partecipare al più otto dispositivi.
Lo scopo di una connessione Bluetooth è quella di mettere in comunicazione i layer che si occupano del livello applicativo, detti Profiles. In altri termini, possiamo immaginare i Profiles come un insieme di protocolli di livello applicativo che utilizzano i layer più bassi dello stack Bluetooth come protocollo di trasporto. Per la realizzazione del nostro esempio, faremo riferimento al Profile denominato Generic Object Exchange Profile (GOEP), all‘interno del quale è definito il protocollo OBEX (OBject EXchange), che permette ad un dispositivo di scambiare file in modalità push con un altro dispositivo. Vale la pena qui ricordare anche il Profile denominato Serial Port Profile (SPP), all‘interno del quale sono definiti i due protocolli L2CAP e RFCOMM, utilizzati per lo scambio di stream di dati [1].
La specifica JSR-82
La specifica JSR-82 definisce lo standard Java per l‘accesso alla tecnologia Bluetooth [2]: è importante sottolineare che tale specifica non rappresenta l‘implementazione di uno stack, ma definisce soltanto le interfacce alle quali un Vendor deve attenersi per realizzare un suo stack conforme allo standard (analogamente a quanto accade ad esempio per la tecnologia JDBC).
Il vantaggio dello sviluppare applicazioni Bluetooth in Java secondo la specifica JSR-82 rispetto all‘uso di API basate sul linguaggio C/C++ (o native) è essenzialmente quello di avere un codice indipendente dello stack e dalle interfaccie di trasmissione radio. Per contro (ovviamente), tali API permettono un controllo limitato sull‘hardware.
JSR-82 è stata progettata per esser supportata da calcolatori dotati di risorse limitate, per cui assume la struttura di un‘estensione (opzionale) della piattaforma J2ME (Java 2 Micro Edition). Nello stesso tempo, è compatibile con la piattaforma J2SE (Java 2 Standard Edition), permettendo anche di far comunicare tramite Bluetooth un componente sviluppato per l‘ambiente J2ME con uno sviluppato per l‘ambiente J2SE.
La JSR-82 consiste nei seguenti package indipendenti [3]:
- javax.microedition.io: per la gestione di connessioni Bluetooth (L2CAP e RFCOMM);
- javax.obex: implementa le funzioni OBEX;
- javax.bluetooth: rappresenta il Core delle API Java Bluetooth, mette a disposizione delle applicazioni funzionalità dei profili Bluetooth Generic Access Profile e Service Discovery.
Segue una breve descrizione delle classi funzionali alla prima parte della nostro esempio, ovvero il discovery di un dispositivo (device discovery):
La classe javax.bluetooth.LocalDevice rappresenta il dispositivo Bluetooth locale. Contiene metodi per accedere alle proprietà generali relative al dispositivo (tra cui indirizzo Bluetooth e il nome) e il metodo setDiscoverable per rendere individuabile il dispositivo, mettendolo in modalità di inquiry scanning.
La classe javax.bluetooth.RemoteDevice rappresenta un dispositivo Bluetooth remoto. Contiene metodi per accedere alle proprietà generali del dispositivo (tra cui indirizzo Bluetooth e il nome) e metodi per l‘autenticazione e la cifratura delle connessioni, secondo quanto previsto dal Generic Access Profile.
La classe javax.bluetooth.DiscoveryAgent fornisce metodi sia per il device discovery sia per il service discovery. Il metodo startInquiry permette di avviare la sessione di inquiry per l‘individuazione dei dispositivi a portata di comunicazione.
L‘interfaccia javax.bluetooth.DiscoveryListener consente all‘applicazione di ricevere gli eventi legati alle richieste di device e service discovery. L‘applicazione utente dovrà fornire un‘implementazione ai metodi di quest‘interfaccia per reagire a tali eventi. In particolare, riguardo alla fase di inquiry, ogni volta che viene trovato un nuovo dispositivo, la libreria Java Bluetooth chiamerà il metodo deviceDiscovered fornendo come argomento il RemoteDevice individuato. Al termine della procedura sarà invocato il metodo inquiryCompleted, avente come argomento un codice che indica se l‘inquiry è stata completata regolarmente o se si è verificato un errore.
Cosa ci serve per iniziare
Per poter iniziare a implementare lo scenario di trasferimento di un‘immagine dal PC al telefono cellulare, abbiamo bisogno di quanto segue:
- Un adattatore Bluetooth USB da collegare al nostro PC (ad esempio il NILOX BLUETOOTH Adapter USB 2.0 CLASSE 1).
- Uno stack Bluetooth conforme alla specifica JSR-82. Lo stack che abbiamo utilizzato per la realizzazione dell‘esempio è BlueCove. Si tratta di una stack open source per piattaforma Windows (lo stack dipende del particolare Sistema Operativo. Per l‘installazione far riferimento alla specifica documentazione). Per lo sviluppo sotto Linux si può far riferimento dello stack BlueZ, anch‘esso open source.
- Le librerie JSR-82. Queste possono essere scaricate dal sito della Sun oppure, come nel nostro caso, possono essere comprese nello packaging dello stack.
- Un IDE per sviluppare applicazioni J2SE (ad esempio Eclipse).
- Un telefono cellulare dotato della tecnologia Bluetooth.
Il discovery di un dispositivo
Ecco il codice Java che realizza il discovery di un dispositivo.
import java.io.*; import java.util.*; import javax.bluetooth.*; public class DiscoveryListenerImpl implements DiscoveryListener { private Hashtable<String, RemoteDevice> devices; public BTDiscoveryListener() { this.devices = new Hashtable<String, RemoteDevice>(); } /* Metodo definito dall‘interfaccia DiscoveryListener */ public void startInquiry() { try { // Accesso al LocalDevice per iniziare la scansione dei dispositivi LocalDevice localDevice = LocalDevice.getLocalDevice(); DiscoveryAgent discoveryAgent = localDevice.getDiscoveryAgent(); // Inizio della scansione dei dispositivi. La libreria avvia un nuovo Thread // per lo svolgimento di questa operazione // discoveryAgent.startInquiry(DiscoveryAgent.LIAC, this); } catch (Exception e) { e.printStackTrace(); } } /* Metodo definito dall‘interfaccia DiscoveryListener: viene invocato automaticamente ogni volta che viene trovato un nuovo dispositivo */ public void deviceDiscovered( javax.bluetooth.RemoteDevice remoteDevice, javax.bluetooth.DeviceClass deviceClass) { // Mettiamo il dispositivo trovato in una Hashtable devices.put(remoteDevice.getBluetoothAddress(), remoteDevice); } /* Metodo definito dall‘interfaccia DiscoveryListener: viene invocato automaticamente quando termina l‘operazione di discovery */ public void inquiryCompleted(int param) { if (param == DiscoveryListener.INQUIRY_COMPLETED || param == DiscoveryListener.INQUIRY_TERMINATED) { // Se l‘operazione di discovery termina correttamente, stampiamo a video i // dispositivi trovati e memorizzati nell‘Hashtable Enumeration enumeration = devices.elements(); while(enumeration.hasMoreElements()) { RemoteDevice device = enumeration.nextElement(); try { System.out.println("Device [" + device.getBluetoothAddress() + ", " + device.getFriendlyName(true) + "]"); } catch (IOException e) { System.err.println("Impossibile recuperare il nome del dispositivo: " + device.getBluetoothAddress()); } } } else { System.out.println("Nessun dispositivo trovato."); } } public void serviceSearchCompleted(int arg0, int arg1) {} public void servicesDiscovered(int arg0, ServiceRecord[] arg1) {} } public class BluetoothExample { public static void main(String[] args) { DiscoveryListenerImpl listener = new BTDiscoveryListener(); listener.startInquiry(); } }
In particolare, la classe DiscoveryListenerImpl rappresenta l‘implementazione dell‘interfaccia javax.bluetooth.DiscoveryListener di cui abbiamo parlato al paragrafo precedente. Secondo tale implementazione, ogni volta che un nuovo dispositivi viene trovato, questo viene inserito in una Hashtable. Al termine dell‘operazione di discovery, nel caso in cui l‘operazione sia terminata correttamente, i dispositivi così trovati verranno stampati a video.
Per testare il codice è necessario assicurarsi che l‘adattatore Bluetooth sia stato collegato al PC e che il telefonino sia stato configurato e predisposto per accettare connessioni Bluetooth.
Conclusioni
In questo articolo abbiamo accennato a quali siano le principali caratteristiche del Bluetooth. Abbiamo visto quale sia il ruolo della specifica JSR-82 nello sviluppo di applicazioni basate su questa tecnologia su piattaforma Java e come, per iniziare a lavorare, sia necessario procurasi un‘implementazione di uno stack Bluetooth compatibile con JSR-82. Abbiamo inoltre sottolineato la necessità di utilizzare un adattatore USB Bluetooth per abilitare il nostro PC a comunicare attraverso questo protocollo. Nel prossimo articolo, vedremo come utilizzare i dispositivi trovati in fase di discovery per inviare loro un file, anzichà© stamparlo semplicemente a video.
Riferimenti
[1] Standard Bluetooth
[2]
http://jcp.org/aboutJava/communityprocess/final/jsr082/
[3]
http://java.sun.com/javame/reference/apis/jsr082