Java & Bluetooth

After an intensive month of work i’m back to my blog to give you what i learn. My actual project concerns embedded systems with tablet PC. Then i had to use Bluetooth in Java. After i read a few articles, using this technology is easy. The problem is to find the an implementation. The JSR 82 is recent and there’s not a lot of open source implementations. I choose 2 which worked great and use the Windows Bluetooth API : BlueCove and BlueSock.

Now the code : it’s like a classic client/server system, based on a specific protocol. The bluetooth protocol is composed in 2 part : layers and profiles. The underlying 2 shemas present it :

Layers Profiles
Layers Profiles

I’m not explain all the Java API concept at now, this book do this better. I just present a little example which use RFCOMM layer and serial port service to send a call command to my phone with AT commands (Technical Docs & Training -> Developers’ Guidelines – AT Commands).
First step, search device arround :

LocalDevice.getLocalDevice().getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC, aDiscoveryListener);

where aDiscoveryListener is an implementation of DiscoveryListener. This method launch a thread and it’s better to use threads to design a client bluetooth API because of time search.
Each founded device call the DiscoveryListener method :

public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod);

The end of search is notified by the method :

public synchronized void inquiryCompleted(int discType)

where discType can be INQUIRY_COMPLETED, INQUIRY_TERMINATED, INQUIRY_ERROR.
Then for each device you have to ask which profiles it provides :

LocalDevice.getLocalDevice().getDiscoveryAgent().searchServices(new int[] {  }, new UUID[] {  }, device, aDiscoveryListener)

where attrSet is the attribute list waiting by profile, uuids the profile list you search (you find UUID predefined list there, but you can declare your own). In setting null to the both arguments, by default you search all profiles and attributes. The device parameter is the target device where the search is make and the aDiscoveryListener is the implementation of DiscoveryListener you use.
Each service founded ask the following DiscoveryListener method :

public void servicesDiscovered(int transID, ServiceRecord[] servRecord)

where transID is the transaction number and servRecord an array of founded profiles.
At the end of search the following method is called :

public synchronized void serviceSearchCompleted(int transID, int respCode).

When you have all serviceRecords, you can call the following method for each serviceRecord:

String url = aServiceRecord.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
StreamConnection conn = (StreamConnection) Connector.open(url);
DataOutputStream dos = conn.openDataOutputStream();
DataInputStream dis = conn.openDataInputStream();

Then now you can send command in the stream, for example i want to make a call from my PC to my phone :

dos.write(new String("ATD<number>;\\r\\n").getBytes());

i read the response :

int c;
while ((c = dis.read()) != -1) {
  System.out.print((char)c);
}

and i close streams

dos.close();
dis.close();
conn.close();

This code is the same in J2ME and J2SE, devices can be what you want (PC, phones, PDA, …) just have to have a JVM and Bluetooth system to which exists an implementation of JSR 82.