This technical article addresses the following tasks:
- Helps demystify some wireless concepts using Bluetooth and the JSR-82 API
- Shows how to run and debug Java ME Bluetooth applications on your desktop computer
- Explains how to read data from a Bluetooth-enabled GPS device
Contents
- | The Big Problem: Where Emulators Fail |
- | Setting Up the Environment |
- | Unraveling Some Mysteries of Bluetooth and JSR-82 |
- | Summary |
Additionally, testing your Java ME Bluetooth applications directly on your JSR-82 device is impractical since you don't have access to the
System.out
for simple debugging of your application. Additionally, the iteration
cycles for developing, compiling, provisioning, and installing the
application on a mobile phone is very time consuming.The good news is that you're going to learn how to construct a low-cost solution that allows you to install, debug, and test your JSR-82 applications on your computer. I'm going to introduce to you the Mpowerplayer, a CLDC emulator for the computer that can be configured to behave like a JSR-82 Bluetooth-enabled phone. With this configuration, the Mpowerplayer will behave just like a JSR-82 Bluetooth-enabled mobile phone, but you'll have access to the
System.out
and have the ability to view stacktraces, both of which are essential in debugging your wireless application.- Required
- The Sun Wireless Toolkit for CLDC. This tool is the defacto standard for developing Java ME applications.
- A Bluetooth-enabled computer. The Bluetooth module for your PC could
either be built-in to the computer or can be attached externally via
the USB port.
- The Mpowerplayer.
This free desktop application is a very good mobile emulator. It is
able to access your Bluetooth hardware on your desktop PC, to execute
the JSR-82 method calls that require access to actual Bluetooth
hardware.
- REQUIRED - A JSR-82 library that supports the Mpowerplayer. I use the Avetana SDK, which works beautifully with the Mpowerplayer.
- A Bluetooth-enabled GPS device. I use the DeLorme Earthmate BT-20.
- The Sun Wireless Toolkit for CLDC. This tool is the defacto standard for developing Java ME applications.
- Optional
- A Java ME phone that supports the JSR-82 API. If you don't know whether your phone supports the JSR-82 API, be sure take a look at this list. It is the best source of information to determine what Java ME APIs the major phone manufacturers support. However, I did notice that the list didn't include any RIM Blackberry devices, which also support the JSR-82 specification.
avetanaBluetoth.jar
file to the
"mpp-sdk\bluetooth" folder - it's just that simple! Later on, you're
going to see screenshots of Mpowerplayer in action.Did you know that once you discover the connection URL for your desired Bluetooth service, then you no longer need to employ the device- and service-discovery processes? If you're unfamiliar with what a Bluetooth connection URL looks like, I have provided an example below:
btspp://001AA3000C19:1;authenticate=false;encrypt=false;master=false
Let us briefly revisit the purposes of the device-discovery and service-discovery processes that apply to all Bluetooth-enabled systems, whether or not if you use the JSR-82 API. The device-discovery process is used to determine what Bluetooth devices are in the vicinity. In the connection URL listed previously, the device represented has the Bluetooth address of
001AA3000C19
. In the example code that will be presented later in this article, I used an inner class named BTUtility
that implements all the necessary JSR-82 Bluetooth API code for device
and service discovery. The code snippet below shows the necessary steps
for device discovery:public BTUtility() { try { LocalDevice localDevice = LocalDevice.getLocalDevice(); discoveryAgent = localDevice.getDiscoveryAgent(); discoveryForm.append(" Searching for Bluetooth devices in the vicinity...\n"); discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this); } catch(Exception e) { e.printStackTrace(); } } public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass cod) { try{ discoveryForm.append("found: " + remoteDevice.getFriendlyName(true)); } catch(Exception e){ discoveryForm.append("found: " + remoteDevice.getBluetoothAddress()); } finally{ remoteDevices.addElement(remoteDevice); } } public void inquiryCompleted(int discType) { if (remoteDevices.size() > 0) { // the discovery process was a success // so let's out them in a List and display it to the user for (int i=0; i<remoteDevices.size(); i++){ try{ devicesList.append(((RemoteDevice)remoteDevices.elementAt(i)).getFriendlyName(true), bt_logo); } catch (Exception e){ devicesList.append(((RemoteDevice)remoteDevices.elementAt(i)).getBluetoothAddress(), bt_logo); } } display.setCurrent(devicesList); } else { // handle this } |
The inner class itself implements the
DiscoveryListener
interface, so its deviceDiscovered()
method will be called every time a remote Bluetooth device has been
found. When the device-discovery process has finally ended, the JVM will
call the inquiryCompleted()
method. Fortunately, I don't
have to deploy this application to my JSR-82 enabled phone to properly
test it. I can test the entire application on my desktop computer using
the Mpowerplayer, as described earlier.Figure 1 shows the Mpowerplayer running my application during the device-discovery process, and Figure 2 shows the state of mobile application after the device-discovery process is finished.
Now that we've taken care of the device-discovery process, and we see that the device that we want to connect to is in the list of available devices, let's take another look at the fully qualified connection URL.
btspp://001AA3000C19:1;authenticate=false;encrypt=false;master=false
As you can see, the device-discovery process lets us know the Bluetooth address (in this case,
001AA3000C19
)
and the friendly name of the remote Bluetooth device (in this case,
Earthmate BT-20 GPS). But we still don't know what the other parameters
are that comprise the connection URL. After all, a single Bluetooth
device can offer multiple services -- for instance, a Bluetooth Access
point can offer both Dialup Networking and Personal Area Networking
services. Therefore, we need to search for the appropriate service that
we want on the selected Bluetooth device.The service-search process is dependent on knowing the type of service that you want. I want to consume serial data from a Bluetooth-enabled GPS device, and the unique identifier for wireless serial services is
0x1101
. The previously mentioned inner class, BTUtility
, has also implemented all the code for service searching. The following snippet shows what is involved.public void run(){ try { RemoteDevice remoteDevice = (RemoteDevice)remoteDevices.elementAt(devicesList.getSelectedIndex()); discoveryAgent.searchServices(attrSet, uuidSet, remoteDevice , this); } catch(Exception e) { e.printStackTrace(); } } public void servicesDiscovered(int transID, ServiceRecord[] servRecord){ for(int i = 0; i < servRecord.length; i++) { DataElement serviceNameElement = servRecord[i].getAttributeValue(0x0100); String _serviceName = (String)serviceNameElement.getValue(); String serviceName = _serviceName.trim(); btConnectionURL = servRecord[i].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false); } display.setCurrent(readyToConnectForm); readyToConnectForm.append("\n\nNote: the connection URL is: " + btConnectionURL); System.out.println("Note: the connection URL is: " + btConnectionURL); } public void serviceSearchCompleted(int transID, int respCode) { if (respCode == DiscoveryListener.SERVICE_SEARCH_COMPLETED) { // the service search process was successful } else { // the service search process has failed } } |
Now, service searching is a blocking I/O operation, so I put the intensive work in the
run()
method of a thread to allow the application to behave nicely. Whenever a
matching service has been found on the remote device, the JVM will call
my servicesDiscovered()
method to let me know so that I
can do something about it. As shown in the following figure, I've found
the service that I want, and I have everything that I need to get the
connection URL.To reiterate a previous point: now that you have determined the connection URL for your desired device, you no longer need to go through the device- and service-discovery processes for subsequent usage of the remote Bluetooth device. All you need to do is open a connection on the URL. After that, you have everything that you need to communicate with the remote Bluetooth device.
Figure 4 shows the operation of another thread-enabled inner class that opens the connection on the URL and then reads the data from the wireless serial port.
Wait a minute. If we're reading serial data from a GPS device, then where are the latitudes, longitudes, and other global-positioning stuff? Is the data corrupted?
Actually, the serial data that you see in Figure 4 is actually encoded in NMEA (National Marine Electronics Association) format, which is the common format for all GPS devices. Part 2 of this technical article shows you how to decode the NMEA data and plot your location on your phone.
Link: http://dsc.sun.com/mobility/apis/articles/bluetooth_gps/part1/
No comments:
Post a Comment