Skip to main content

skip to main content

developerWorks  >  Java technology  >

Add a Bluetooth text protocol to J2ME apps

Learn how to allow embedded devices to share information and events across a Bluetooth PAN

developerWorks
Document options

Document options requiring JavaScript are not displayed

Sample code


New site feature

Check out our new article design and features. Tell us what you think.


Rate this page

Help us improve this content


Level: Introductory

Chris Bygrave (bygravec@uk.ibm.com), Software Engineer, IBM

21 Mar 2006

With the continuing boom of mobile devices in the communications and gaming industries, as well as the software trend toward ad hoc and peer-to-peer networks, the ability to target heterogeneous devices for networked applications (whether gaming, productivity, or information sharing) is a big advantage. In this article, learn how to use and integrate the Bluetooth API (which was introduced into Java™ 2 Platform, Micro Edition [J2ME] through JSR 82) into your own applications. Here, you'll find a complete Bluetooth device discovery, pairing, and messaging implementation.

As innovation continues to expand in the mobile device field, and as companies integrate chips into more consumer devices (those not traditionally associated with computing), the opportunities to tie these devices together to create smart environments are increasing. In this article, see how a package based on the Bluetooth Java APIs lets these devices trade arbitrary text-based messages, and presents a simple, useful API to the client program.

Why Bluetooth?

Bluetooth is a maturing technology targeted at building personal area networks (PANs) and connecting devices with relatively low bitrate requirements cheaply and without wires. Bluetooth is available in multiple flavors (or classes) with varying power requirements (and proportionally varying range). These attributes make it ideal both for ad hoc peer-to-peer networking between mobile devices and for networking between static devices, such as living-room consumer electronics.

What can you do with PANs?

PANs solve different problems from LANs, WANs, and the Worldwide Web; PANs' problems are often driven by convenience. Perhaps the technology's most attractive uses are wireless mobile phone headsets and keyless car entry systems. Neither of these solutions require Bluetooth or any other wireless technology, but by providing a cost-effective solution that makes the standard of living just that much higher, you can forge new markets.



Back to top


The btevents package

To tie together disparate collections of devices from multiple manufacturers, you need a simple, flexible method of communication. Technologies such as Object Exchange (OBEX) deal with the transmission of binary data, which, while crucial for many Bluetooth applications, is not ideal for implementing simple message protocols. Also, you need to work with the concepts of device and service discovery, which are essential to building ad hoc peer-to-peer connections between devices. The btevents package provides an easy, repeatable technique to enable simple textual communication between Bluetooth devices.

For example, consider that you might want your television volume to reduce automatically when the phone rings. Listings 1 and 2 outline how you can use the btevents package to enable the two devices to communicate without requiring a huge amount of boilerplate code in the client application.

First, take a look at the code running on the telephone.


Listing 1. Sample code for a telephone

package bluetooth.livingroom;

import com.ibm.btevents.*;

public class TelephoneMonitor extends MIDlet implements BTEventListener,
                                                        PhoneListener {

    private BTManager btManager;

    public TelephoneMonitor() {
        btManager = new BTManager(this);
    }

    public void incomingCall(PhoneEvent event) {
        btManager.sendMessage(
                "bluetooth.livingroom.TelevisionMonitor",
                "incomingCall:"+event.getCaller()
        );
    }

    public void callEnded(PhoneEvent event) {
        btManager.sendMessage(
                "bluetooth.livingroom.TelevisionMonitor",
                "callEnded:"+event.getDuration()
        );
    }

    public void messageReceived(BTEvent event) {}
    public void messageSent(BTEvent event) {}
    public void devicesDiscovered(BTEvent event) {}
    public void diagnosticMessage(BTEvent event) {}

}

The TelephoneMonitor creates a BTManager object and passes in a BTEventListener object. In this case, the telephone isn't interested in any of the events generated by the Bluetooth communication; for example, look at the TelevisionMonitor. The interesting code in this class is in the incomingCall() and callEnded() methods. These methods are called to handle a notional PhoneEvent, which provides basic details about the call, such as caller ID and call duration. The only necessary action for these methods is to notify the TelevisionMonitor by transmitting the relevant message using the BTManager object.

Now, take a look at the other side:


Listing 2. Sample code for a television

package bluetooth.livingroom;

import com.ibm.btevents.*;

public class TelevisionMonitor extends MIDlet implements BTEventListener {

    private BTManager btManager;

    public TelevisionMonitor() {
        btManager = new BTManager(this);
    }

    private void reduceVolume() {
    ...
    }

    private void restoreVolume() {
    ...
    }

    private void displayMessage() {
    ...
    }

    public void messageReceived(BTEvent event) {
        String message[] = event.getMessage().split(":");
        if (message[0].equals("incomingCall")) {
            displayMessage("Incoming call from "+message[1]);
            reduceVolume();
        } else if (message[1].equals("callEnded")) {
            displayMessage("Call ended, lasted "+message[1]);
            restoreVolume();
        }

    public void messageSent(BTEvent event) {}
    public void devicesDiscovered(BTEvent event) {}
    public void diagnosticMessage(BTEvent event) {}

}

Here the client code must simply act on the received messages. If it receives an incomingCall message, the code reduces the volume and displays the caller on screen. If it receives a callEnded message, the code restores the volume and displays the call duration.

In each code block above, you make assumptions about access to device-specific APIs and event mechanisms such as the TelephoneMonitor's PhoneEvent objects and the TelevisionMonitor's ability to put a message on the screen and control volume. These functions are highly device-specific and may not be consistent between devices of similar function. However, you can localize these device-specific functions to the device; you don't need the TV to be aware of, or understand, PhoneEvents. All you do need is for device manufacturers to recognize a logical connection between two devices and code accordingly. In this case, the logical connection is that the TV would like to know when the user is on the telephone.

Next, take a look at how the btevents package handles these messages.



Back to top


The btevents package in detail

The btevents package is a layer around the Java Bluetooth API introduced in JSR 82 (see Resources for more information). It takes the complexity out of implementing a simple, textual protocol between devices. As the name suggests, information is delivered in the form of events. Because PANs can be very dynamic, with devices dropping into and out of range without notice, any software using them must follow an asynchronous design to prevent pauses and hangs, particularly those presenting GUIs to users. The event mechanism in the Java language is the perfect tool for such an environment.

Figure 1 shows the important elements of the btevents package.


Figure 1. Package overview
Installing toolkits

The TelephoneMonitor and TelevisionMonitor classes both created an instance of a BTManager class in their constructors, so you should start by showing what the BTManager class does (see Listing 3).


Listing 3. The BTManager class

package com.ibm.btevents;

public class BTManager {

    private BTTransmitter transmitter;
    private BTReceiver receiver;
    private BTDiscoverer discoverer;
    
    public BTManager(BTEventListener listener) {
        transmitter = new BTTransmitter();
        transmitter.addBTEventListener(listener);
        transmitter.start();
        receiver = new BTReceiver();
        receiver.addBTEventListener(listener);
        receiver.start();
        discoverer = new BTDiscoverer();
        discoverer.addBTEventListener(listener);
        discoverer.start();
    }

    public void startDiscovery() {
        discoverer.searchForDevices();
    }

    public void sendMessage(String remoteName, String message)
                                   throws DeviceNotFoundException {
        transmitter.sendMessage(remoteName, message);
    }
}

As you can see, this class creates and starts three separate threads, each one with a specific task. Implementing these functions inside threads eliminates any possibility of the client application locking up due to a connection dropping mid-transmission.

Each of these three threads performs a subset of the tasks necessary to enable two-way communication, as well as device and service discovery.

BTDiscoverer

Now, take a look at the BTDiscoverer thread. This thread allows the client application to request a local search at any point, making search results available asynchronously using a BTEvent. The most important code is the API call to initiate a discovery session:

localDevice.getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC, this);

This API call generates its own set of events, which requires the BTDiscoverer class to implement the DiscoveryListener interface. To keep the btevents interface clean and consistent, these events are handled internally. Any discovery-related events that need to be externalized are converted into BTEvents and fired by BTDiscoverer.

BTReceiver

The BTReceiver class plays a role familiar to anyone who has written a server application using the Worker Thread design pattern (see Resources for more information). It creates a StreamConnectionNotifier object and listens on this object for incoming connections. When BTReceiver detects a connection, the class passes the StreamConnection object off to a worker thread to process the input and fire a message-received BTEvent to any registered BTEventListeners.

StreamConnections are not the only option for creating connections between two Bluetooth devices. In fact, there are three different connection types available, as shown in Table 1.


Table 1. Types of bluetooth connections
Connection identifierExpanded name
btgoepGeneral object exchange profile
btl2capLogical link control and adaption layer protocol
btsppSerial port profile

First, btgoep transmits binary data, so it is not appropriate for string-based communication. btl2cap requires more legwork from developers, setting and working around maximum message sizes. However, btspp hides these complexities from the developer, so this is the logical connection choice for a project aimed at simplifying the developer's process.

The format of the connection URL passed to the javax.microedition.io.Connector.open(connURL) call decides the type of connection established:

protected static final String BT_PROTOCOL = "btspp";
protected static final String BT_ID = "1234";
server = (StreamConnectionNotifier)Connector.open( BT_PROTOCOL + "://localhost:" + BT_ID);

The reference to localhost in the connection URL is also crucial, as this instructs the open() call to create a server connection. If you use a remote address, you create a client connection.

BTTransmitter

The BTTransmitter class, as the name suggests, deals with the transmission of messages to remote devices. Client applications can submit messages for transmission through the BTManager class. These are passed through to the BTTransmitter class and added to a message queue vector. The BTTransmitter thread monitors the queue and sends any messages it finds using the Connector class. To do this, it must retrieve the services from the remote target. This process is similar to device discovery.

localDevice.getDiscoveryAgent().searchServices( null, filter, message.getRemote(), this);

After this search is complete, you can use the ServiceRecord obtained to create an OutputStream into which you can write the message:

out = Connector.openOutputStream( record.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false));
out.write(message.getMessage().getBytes());
fireMessageSentEvent(message.getMessage());

After the code transmits the message, it fires events to registered listeners to notify them of the transmission.

Due to the unreliable nature of PANs, the BTTransmitter thread will retry a limited number of times to transmit a message that fails. After five attempts, it assumes that the device is no longer in range and drops the message -- such is the nature of ad hoc networking!

Using the package

Now comes the interesting work: making devices talk to each other! You need just a small amount of boilerplate code to get a device up and running with the btevents package. Listing 4 shows a simple pseudocode overview.


Listing 4. Using the btevents package

import com.ibm.btevents.*;

public class MyBTClass implements BTEventListener {
    
    ...
    private BTManager manager;
    
    public MyBTClass() {
        ...
        manager = new BTManager();
        manager.addBTEventListener(this);
        ...
    }

    public void messageReceived(BTEvent event) {
        ...      
    }

    public void messageSent(BTEvent event) {
        ...
    }

    public void devicesDiscovered(BTEvent event) {
        ...
    }

    public void diagnosticMessage(BTEvent event) {
        ...
    }

    public void errorMessage(BTEvent event) {
        ...
    }

}

The attached package contains a simple com.ibm.btevents.ut.BTTestsMIDlet class, which implements the above in a simple J2ME MIDlet suitable for deployment on JSR82-enabled J2ME devices.



Back to top


Conclusion

In this article, you've seen how you can add a Bluetooth transport layer to client applications without overburdening the client with boilerplate code and asynchronous messaging considerations. You can achieve a clean factoring of function and leave code simple to develop and maintain.




Back to top


Downloads

DescriptionNameSizeDownload method
Source code for the btevents packagebtevents-src.zip10KBHTTP
A deployable MIDlet sample suitebtevents.jar13KBHTTP
Information about download methods


Resources

Learn

Discuss


About the author

Chris Bygrave works at the IBM Java Technology Center (JTC) in Hursley (United Kingdom). His current projects include developing IBM's Java 2 Platform, Standard Edition (J2SE) implementations.




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot Slashdot it!



Back to top