Thursday, March 29, 2012

Accessing GPS receiver from mobile phone via bluetooth

Accessing GPS receiver from mobile phone via bluetooth

The goal of this project is to read data sent by a GPS receiver via bluetooth on a mobile phone. The data is being transmitted using the bluetooth serial port profile. The GPS receiver uses the NMEA-0183 protocol. This document contains only a description of the mobile device side process that is necessary to get the data from the receiver.
Used Software
  • J2ME (MIDP 2.0, CDLC 1.0)
Used Hardware
  • Nokia 6230 (software version 4.44)
  • RoyalTek BlueGPS (RBT-3000)
Source code
The source code includes a thread-based implementation of the communication between mobile device and GPS receiver. There is a test midlet in Starter.java which displays some information. Description
Establishing connection
The first step is to connect to the bluetooth GPS receiver device. In order to keep it simple, we assume that the bluetooth device address is known (0002c727fc56 in this example). The URL consists of three different parts: URL scheme (btspp: bluetooth serial port profile), bluetooth device address and port.
In the next step an InputStreamReader is being created using the opened connection and its openInputStream() method. Note that both methods may throw an IOException.
        String url = "btspp://0002c727fc56:1";

        javax.microedition.io.StreamConnection connection =
(StreamConnection) Connector.open(url, Connector.READ);


        java.io.InputStreamReader reader =
 new InputStreamReader(connection.openInputStream());

    
Reading data
In this section the characters sent by the GPS receiver are sequentially read in and added to a string until a carriage return character (ASCII code 13) occurs which indicates the end of line. In order to make further processing possible the last character (line feed, ASCII code 10) of the result string is cut off.
        String output;

        int input;



        while ((input = reader.read()) != 13)

            output += (char) input;



        output = output.substring(1, output.length() - 1);
    
Processing data
Each line read in corresponds to a record defined in the NMEA-0183 protocol and can be parsed in further processing steps (see simple J2ME NMEA parser for more details).
Conclusion
Although the process of connecting to the bluetooth device and receiving data is not very complicated there are some difficulties regarding the connection and the used protocol. If the connection is hold up while processing the incoming data (which may take a while) the receiver continually sends data. Depending on the hardware this behavior might cause a buffer overflow (eg on Siemens S65). Therefore it is recommended to disconnect from the GPS receiver while processing data if the processing takes too long and the position data is needed only once in while.

References

Link: http://old.hcilab.org/documents/tutorials/BT_GPS/BT_GPS.htm

 

Wednesday, March 21, 2012

Bluetooth GPS simulator for J2ME phone

Bluetooth GPS simulator for J2ME phone

 

This BlueGPS application is used to simulate Bluetooth GPS receiver on J2ME phone. It will turn a bluetooth enable phone become a bluetooth GPS receiver.

If you want to develop a J2ME application for mobile phone to read NMEA sentence from a bluetooth GPS receiver, you need to have a bluetooth GPS receiver hardware.

If you do not have a bluetooth GPS receiver hardware, will it stop you from develop a GPS application for mobile phone?

I do not have bluetooth GPS receiver hardware but I want to develop a GPS application for mobile phone so I am looking for a bluetooth GPS simulator.

I spend a lot of time to search on the net. However, I could not find any bluetooth GPS simulator available anywhere. So I wrote a simple application BlueGPS that can run on any bluetooth enable phone to simulate a bluetooth GPS receiver.

I installed and ran BlueGPS on one mobile phone. Then I wrote another GPS application and ran on another mobile phone. The GPS application on the second phone used bluetooth connection to retrieve NMEA sentences from the first phone.

BlueGPS did help me a lot when I develop GPS apllication without having bluetooth GPS receiver hardware. I hope it helpful for you as well even in case you already have a bluetooth GPS receiver hardware because BlueGPS will help you to test your GPS application faster (No need to go outdoor, no need to wait for satellites fix, you can simulate any type of sentences, valid or invalid sentences, error or incomplete sentences…)

Here is the source code of BlueGPS:
/************************************************************
Description:
This BlueGPS application is used to simulate Bluetooth GPS receiver on J2ME phone. It will turn a bluetooth enable phone become a bluetooth GPS receiver.
When this BlueGPS application is running on a phone, it will wait for bluetooth connection from other bluetooth device.
When a bluetooth connection is made, BlueGPS will send NMEA sentences continuously.
Created By: ThreeSearch 2007-01-29
www.digitalmobilemap.com
*************************************************************/
/*————————————————–
* BlueGPS.java
*
*————————————————-*/
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;
import javax.bluetooth.*;
import javax.microedition.io.*;
import java.io.*;
public class BlueGPS extends MIDlet implements Runnable
{
private Display display; // The display
private TestCanvas canvas; // Canvas
LocalDevice localDevice;
ServiceRecord serviceRecord;
StreamConnectionNotifier notifier = null;
StreamConnection conn = null;
private static final UUID L2CAP_UUID = new UUID(256L); // simulate L2CAP service provided by real bluetooth GPS receiver.
private static String serverUrl = “btspp://localhost:” + L2CAP_UUID + “;authorize=false;encrypt=false”; // simulate no authorize and no encrypt required by real bluetooth GPS receiver.
OutputStream output;
InputStream input;
String[] sentence;
// Time in ms to wait until send next NMEA Sentence.
private static final long BREAK = 400;
public BlueGPS()
{
display = Display.getDisplay(this);
canvas = new TestCanvas(this);
display.setCurrent(canvas);
}
protected void startApp()
{
new Thread(this).start();
}
public void run()
{
DataInputStream in;
int i = 0, numSentence = 0;
String str;
long time;
canvas.message = “Starting BlueGPS…”;
canvas.paintScreen();
try
{
conn = null;
localDevice = LocalDevice.getLocalDevice();
localDevice.setDiscoverable(DiscoveryAgent.GIAC);
notifier = (StreamConnectionNotifier)Connector.open(serverUrl);
}
catch (BluetoothStateException e)
{
canvas.message = e.getMessage();
canvas.paintScreen();
return;
}
catch (IOException e)
{
canvas.message = e.getMessage();
canvas.paintScreen();
return;
}
numSentence = 18; // number of sentences
sentence = new String[numSentence];
// real bluetooth GPS recevier send a lot of different sentence types
// I only simulate 3 important sentence types:
// $GPGSA - GPS DOP and active satellites. This sentence provides details on the nature of the fix
// $GPGGA - Essential fix data which provide 3D location and accuracy data
// $GPRMC - Recommended Minimum Sentence C which provide essential gps pvt (position, velocity, time) data.
// you can modify these NMEA sentences as you wish
// you read more detail about NMEA sentence types here NMEA sentences
sentence[0] = “$GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39″;
sentence[1] = “$GPGGA,123519,0117.349,N,10350.488,E,1,08,0.9,545.4,M,46.9,M,,*47″;
sentence[2] = “$GPGGA,123519,0117.358,N,10350.495,E,1,08,0.9,545.4,M,46.9,M,,*47″;
sentence[3] = “$GPRMC,130843,A,0117.3740,N,10350.5070,E,005.0,315.0,011206,000.0,E*6F”;
sentence[4] = “$GPRMC,130844,A,0117.3890,N,10350.5190,E,005.0,315.0,011206,000.0,E*68″;
sentence[5] = “$GPRMC,130845,A,0117.3960,N,10350.5290,E,005.0,315.0,011206,000.0,E*69″;
sentence[6] = “$GPRMC,130846,A,0117.3980,N,10350.5420,E,005.0,315.0,011206,000.0,E*6A”;
sentence[7] = “$GPRMC,130847,A,0117.3970,N,10350.5460,E,005.0,315.0,011206,000.0,E*6B”;
sentence[8] = “$GPRMC,130848,A,0117.3940,N,10350.5640,E,005.0,315.0,011206,000.0,E*64″;
sentence[9] = “$GPRMC,130849,A,0117.3710,N,10350.6080,E,005.0,315.0,011206,000.0,E*65″;
sentence[10] = “$GPRMC,130850,A,0117.3420,N,10350.6470,E,005.0,315.0,011206,000.0,E*6D”;
sentence[11] = “$GPRMC,130851,A,0117.3200,N,10350.6740,E,005.0,315.0,011206,000.0,E*62″;
sentence[12] = “$GPRMC,130852,A,0117.2900,N,10350.7060,E,005.0,315.0,011206,000.0,E*6C”;
sentence[13] = “$GPRMC,130853,A,0117.2670,N,10350.7310,E,005.0,315.0,011206,000.0,E*6D”;
sentence[14] = “$GPRMC,130854,A,0117.2510,N,10350.7620,E,005.0,315.0,011206,000.0,E*6F”;
sentence[15] = “$GPRMC,130855,A,0117.2690,N,10350.7800,E,005.0,315.0,011206,000.0,E*68″;
sentence[16] = “$GPRMC,130856,A,0117.2930,N,10350.8010,E,005.0,315.0,011206,000.0,E*69″;
sentence[17] = “$GPRMC,130857,A,0117.3170,N,10350.8210,E,005.0,315.0,011206,000.0,E*6A”;
try
{
canvas.message = “Waiting to send…”;
canvas.sentence = sentence[0];
canvas.paintScreen();
conn = notifier.acceptAndOpen();
output = conn.openOutputStream();
}
catch (IOException e)
{
canvas.message = e.getMessage();
canvas.paintScreen();
}
i = 0;
while (true)
{
try
{
canvas.message = “Waiting to send…”;
canvas.sentence = sentence[i];
canvas.paintScreen();
output.write(sentence[i].getBytes());
// simulate carry return character
output.write(13);
output.write(10);
output.flush();
}
catch (IOException e)
{
canvas.message = e.getMessage();
canvas.paintScreen();
}
try
{
Thread.sleep(BREAK); // wait for a while before send next sentence
}
catch (Exception e) {}
if (i < numSentence - 1)
i++;
else
i = 0;
} // while (true)
}
protected void pauseApp() { }
protected void destroyApp( boolean unconditional ) { }
public void exitMIDlet()
{
destroyApp(true);
notifyDestroyed();
}
}
/*————————————————–
* Class TestCanvas
*
*————————————————-*/
class TestCanvas extends Canvas implements CommandListener
{
private BlueGPS midlet;
public String message;
private int width, height;
String sentence;
/*————————————————–
* Constructor
*————————————————-*/
public TestCanvas(BlueGPS pmidlet)
{
midlet = pmidlet;
setFullScreenMode(true);
width = getWidth();
height = getHeight();
message = new String();
sentence = new String();
setCommandListener(this);
}
public void paintScreen()
{
repaint();
serviceRepaints();
}
/*————————————————–
* Paint canvas
*————————————————-*/
protected void paint(Graphics g)
{
g.setColor(0xCCFFCC);
g.fillRect(0, 0, width, height);
g.setColor(0×0000FF);
g.drawString(message,0,g.getFont().getHeight()*1,g.BASELINE|g.LEFT);
g.drawString(sentence,0,g.getFont().getHeight()*2,g.BASELINE|g.LEFT);
g.drawString(”Press any key to exit”,0,g.getFont().getHeight()*3,g.BASELINE|g.LEFT);
}
protected void keyPressed(int key)
{
midlet.exitMIDlet();
}
public void commandAction(Command c, Displayable d) {}
}

How to use BlueGPS:

1. You need to have 2 bluetooth enable phones.

2. Create a project BlueGPS in Sun Java Wireless Toolkit. Project’s settings as follow:

JSR082: true <– this setting to enable bluetooth API JSR082
JSR172: false
JSR177: false
JSR179: false
JSR184: false
JSR211: false
JSR75: false
MMAPI: false
WMA0: true
WMA1.1: false
WMA2.0: false
configuration: CLDC1.0
platform: CUSTOM
profile: MIDP2.0

3. Copy the Bluetooth’s source code above and save it as BlueGPS.java in src folder of BlueGPS project.

4. Open BlueGPS.java and modify NMEA sentences to latitude and longitude of your area.

5. Compile BlueGPS and generate .jar file

6. Install and run BlueGPS.jar on one mobile phone.

7. Install and run your GPS application on another mobile phone. Your GPS application need to be programmed to discover/connect/retrieve NMEA sentence from BlueGPS run on the first phone. You can read a sample program here: How to connect and retrieve NMEA sentences from bluetooth GPS

8. You can download BlueGPS to test with your GPS application from here: Download BlueGPS.rar

9. You can buy Connect Phone to GPS Source Code Templates from here: www.j2megps.com




Link: http://www.digitalmobilemap.com/bluetooth-gps-simulator-for-j2me-phone

Tuesday, March 20, 2012

Bluetooth Overview

Bluetooth Overview

 The Bluetooth wireless technology is a low cost, short range, and low power specification for an ad-hoc network for data and voice communication in any place of the world. It was created by Ericsson in 1994 to provide wireless connection between devices and mobile phones. The given name and logotype comes from a Scandinavian king called Harold Bluetooth (Blatand'). It is based on 2.4GHz unlicensed frequency. This radio is not like the mobile phone radio used to connect Telecom suppliers. On average the distance from transmitter to receiver is 10 Meters (depending of Bluetooth Radio classification by Bluetooth SIG). It can also be 100 Meters.

Bluetooth Profiles

The main reason for use of Bluetooth is the cheap connection cost and the ability to connect to a range of electronic devices, not just PC's and other mobile phones, so most Bluetooth devices do not need an Operating System to support them. It is possible because the technology is profile-based which defines a set of protocols for each feature enabled.
These are some of the defined profiles:
- GAP: Generic Access Profile (mandatory for all devices - enables inquiry, service discovery, etc.)
- PAN: Personal Area Network Profile
- SPP: Serial Port Profile (over RFCOMM emulates RS-232)


http://www.developer.nokia.com/Community/Wiki/images/8/8b/Bt_protocol_stack.JPG?20070416100353
If there is a group of Bluetooth devices supporting the PAN profile, they can create a network where one device is the 'master' and the rest of devices are 'slaves'. This network is called "Piconet" and it has 1 master and a max of 7 slaves. It is possible for a slave from a given piconet, to become master for a different piconet. Then, it is possible to merge piconets creating a "Scatternet". It is possible to create a max of 10 Scatternets.
A common use of Bluetooth is to connect a Bluetooth headset to a phone. It means you do not need wires to connect to your phone. One of the latest development is to use specific mobile phones as stereo music players via Bluetooth using specific headphones which support the Advanced Audio Distribution Profile (A2DP) for Bluetooth 2.0.
These are some example devices that use Bluetooth to communicate: - Headsets (Audio Profile)
- GPS (SPP)
- Printers (SPP)
- Virtual Cards, Notes (OBEX)

Monday, March 19, 2012

Getting Started with Java and Bluetooth

Getting Started with Java and Bluetooth


You're a Java developer, and you've finally got yourself a
Bluetooth device. Maybe it's a cell phone, a PDA, or a USB dongle for
your PC. Or perhaps you've heard a lot about Bluetooth, but you aren't
sure what exactly you can do with it. In either case, you've had some
exposure to Bluetooth, and now you're ready to start flexing your programming
muscles with the technology. Great! The purpose of this article is to give you
a good introduction to the Bluetooth protocol, including an overview of its
protocol layers and profiles. We'll also cover the the classes and methods
of JSR-82, the official Java Bluetooth API. Finally, we'll wrap things
up by describing what software that you'll need in order to get started.

What is Bluetooth?

What exactly is Bluetooth? Well, simply stated, Bluetooth is a wireless communication
protocol. Since it's a communication protocol, you can use Bluetooth to communicate
to other Bluetooth-enabled devices. In this sense, Bluetooth is like any other
communication protocol that you use every day, such as HTTP, FTP, SMTP, or IMAP. Bluetooth
has a client-server architecture; the one that initiates the connection is the
client, and the one who receives the connection is the server. Bluetooth is a
great protocol for wireless communication because it's capable of transmitting
data at nearly 1MB/s, while consuming 1/100th of the power of Wi-Fi.
In order for Bluetooth devices to communicate properly, they all need to
conform to the Bluetooth specification. The Bluetooth specification, like any
other spec, defines the standard that a Bluetooth device should adhere to, as
well as rules that need to be enforced when communicating. You can download
the specification documents at the official Bluetooth
web site
. The Bluetooth protocol stack and profiles together comprise the
Bluetooth specification.

The Bluetooth Protocol Stack

The Bluetooth stack is the software or firmware component that has direct access
to the Bluetooth device. It has control over things such as device settings, communication
parameters, and power levels for the Bluetooth device. The stack itself consists
of layers, and each layer of the stack has a specific task in the overall functionality
of the Bluetooth device. Since Bluetooth device manufacturers are not required to use all of the layers in the stack, we're only going to cover the main ones that are implemented in almost every Bluetooth device.
  • HCI is the Host Controller Interface. This layer is the interface between
    the radio and the host computer.
  • L2CAP stands for Logical Link Controller Adaptation Protocol. This layer
    is the multiplexer of all data passing through the unit. Audio signals, however,
    have direct access to the HCI.
  • SDP is the Service Discovery Protocol. The SDP layer is used to find services
    on remote Bluetooth devices.
  • RFCOMM is widely known as the virtual serial port protocol.
  • OBEX is the object exchange protocol.

Bluetooth Profiles

Bluetooth Profiles were created to allow different Bluetooth devices to interoperate.
For instance, let's say that you own a Bluetooth-enabled PDA and a Bluetooth-enabled wireless phone. Both devices have Bluetooth stacks. How can you
tell if those two devices will allow you to synchronize the phone lists between
each other? How will you know if you can send a phone number from the PDA to
the phone? And most importantly, how can you determine if these devices will
allow you to browse the Internet from the PDA, using the phone as a wireless modem?
A Bluetooth profile is a designed set of functionality for Bluetooth devices.
For instance, using the examples listed above, the phone and the PDA must both
support the Synchronization Profile in order to synchronize data between them.
In order to send object data such as a .vcf file from the PDA to the phone, then both
devices need to have the Object Push Profile implemented. Finally, the PDA
and the wireless phone must both support the Dialup Networking Profile in order
for the PDA to wirelessly browse the Internet via the phone. If you want your
Bluetooth-enabled devices to interact, having a Bluetooth stack is not good
enough -- they also need to conform to a particular profile.
A word of caution here: do not get Bluetooth profiles confused with J2ME profiles. J2ME profiles are a set of Java classes that extend the functionality of a J2ME
Configuration. For instance, the MID Profile is a set of Java classes that extend
the functionality of the Connected Limited Device Configuration. On the other
hand, a Bluetooth profile can be implemented in any language and on any platform,
because it refers to a defined set of functionality for a Bluetooth-enabled
device. So the Object Push Profile can be implemented on a Palm OS PDA in C++,
and can be implemented on a Bluetooth-enabled printer in assembly language.
For those of you who are familiar with RUP methodology, Bluetooth Profiles are
also called Bluetooth Use Cases.

Java Bluetooth Application Concepts

The basic concepts of any Bluetooth application (Java or otherwise) consist
of the following components:
  • Stack Initialization
  • Device Discovery
  • Device Management
  • Service Discovery
  • Communication
The Java Bluetooth Specification adds a special component to the mix called
the Bluetooth Control Center (BCC), which is outside of the scope of this article.
Stack Initialization
Before you can do anything, you need to initialize your stack. Remember,
the stack is the piece of software (or firmware) that controls your Bluetooth
device. Stack initialization can consist of a number of things, but its main
purpose is to get the Bluetooth device ready to start wireless communication.
Every vendor handles stack initialization differently, so we'll cover how to
initialize the stack using the Atinav Java Bluetooth SDK.
 
import javax.bluetooth.*;
import javax.microedition.io.*;
import com.atinav.BCC;

public class WirelessDevice implements DiscoveryListener {
    LocalDevice localDevice = null; 
    
    public WirelessDevice (){ 
        //setting the port number using Atinav's BCC
        BCC.setPortName("COM1"); 
        
        //setting the baud rate using Atinav's BCC
        BCC.setBaudRate(57600);
        
        //connectable mode using Atinav's BCC
        BCC.setConnectable(true);
        
        //Set discoverable mode using Atinav's BCC 
        BCC.setDiscoverable(DiscoveryAgent.GIAC); 
        
        try{
            localDevice = LocalDevice.getLoaclDevice(); 
        }
        catch (BluetoothStateException exp) {
        }
        
        // implementation of methods in DiscoveryListener class
        // of javax.bluetooth goes here
        
        // now do some work
    }
}
Device Management
LocalDevice and RemoteDevice are the two main classes
in the Java Bluetooth Specification that allow you to perform Device Management.
These classes give you the ability to query statistical information about
your own Bluetooth device (LocalDevice) and information
on the devices in the area (RemoteDevice). The static method LocalDevice.getLocalDevice()
returns an instantiated LocalDevice object for you to use. In order to get the
unique address of your Bluetooth radio, just call getBluetoothAddress() on your
local device object. The Bluetooth address serves the same purpose of the MAC
address on the network card of your computer; every Bluetooth device has a unique
address. If you want other Bluetooth devices in the area to find you, then call
the setDiscoverable() method in LocalDevice object. In a nutshell, that's about all it takes to perform Device Management with the
Java Bluetooth Specification APIs. Now, let's take a look at the concept in Bluetooth
that allows you to discover other Bluetooth devices: device discovery.
Device Discovery
Your Bluetooth device has no idea of what other Bluetooth devices are in
the area. Perhaps there are laptops, desktops, printers, mobile phones, or PDAs
in the area. Who knows? The possibilities are endless. In order to find out,
your Bluetooth device will use the Device Discovery classes that are provided
into the Java Bluetooth API in order to see what's out there.
Let's take a look at the two classes needed in order for your Bluetooth
device to discover remote Bluetooth devices in the area: DiscoveryAgent and
DiscoveryListener.
After getting a LocalDevice object, just instantiate a DiscoveryAgent
by calling LocalDevice.getDiscoveryAgent().
LocalDevice localdevice = LocalDevice.getLocalDevice(); 
DiscoveryAgent discoveryagent = localdevice.getDiscoveryAgent();
The are multiple ways to discover remote Bluetooth devices, but to be brief,
I'll just show you one particular way. First, your object must implement the
DiscoveryListener interface. This interface works like any listener, so it'll
notify you when an event happens. In this case, you'll be notified when Bluetooth
devices are in the area. In order to start the discovery process, just call
the startInquiry() method on your DiscoveryAgent. This method is non-blocking,
so you are free to do other things while you wait for other Bluetooth devices
to be found.
When a Bluetooth device is found, the JVM will call the deviceDiscovered()
method of the class that implemented the DiscoveryListener interface.
This method will pass you a RemoteDevice object that represents the device discovered by
the inquiry.
Service Discovery
Now that you know how to find other Bluetooth devices, it would be really nice
to see what services that those devices offer. Of course, if the RemoteDevice
is a printer, then you know that it can offer a printing service. But what if
the RemoteDevice is a computer? Would it readily come to mind that you can also print to a
printer server?
That's where Service Discovery comes in. You can never be sure what services
a RemoteDevice may offer; Service Discovery allows you to find out what they are.
Service Discovery is just like Device Discovery in the sense that you use the
DiscoveryAgent to do the "discovering." The searchServices()
method of the DiscoveryAgent class allows you to search for services
on a RemoteDevice. When services are found, the servicesDiscovered()
will be called by the JVM if your object implemented the DiscoveryListener
interface. This callback method also passes in a ServiceRecordobject
that pertains to the service for which you searched. With a ServiceRecord
in hand, you can do plenty of things, but you would most likely would want to
connect to the RemoteDevice where this ServiceRecord originated:
String connectionURL = servRecord[i].getConnectionURL(0, false);
Service Registration
Before a Bluetooth client device can use the Service Discovery on a Bluetooth
server device, the Bluetooth server needs to register its services internally
in the Service Discovery database (SDDB). That process is called Service Registration.
This section will discuss what's involved for Service Registration for a Bluetooth
device, and I'll also give you a rundown of the classes needed to accomplish this.
Note: In a peer-to-peer application, such as a file transfer or chat application,
be sure to remember that any device can act as the client or the server, so
you'll need to incorporate that functionality (both client and server) into
your code in order to handle both scenarios of Service Discovery (i.e., the client)
and Service Registration (i.e., the server). Here's a scenario of what's involved
to get your service registered and stored in the SDDB.
  1. Call Connector.open() and cast the resulting Connection to a StreamConnectionNotifier.
    1. Connector.open() creates a new ServiceRecord and sets some attributes.
  2. Use the LocalDevice object and the StreamConnectionNotifier to obtain the ServiceRecord that was created by the system.
  3. Add or modify the attributes in the ServiceRecord (optional).
  4. Use the StreamConnectionNotifier and call acceptAndOpen() and wait for Bluetooth clients to discover this service and connect.
    1. The system creates a service record in the SDDB.
  5. Wait until a client connects.
  6. When the server is ready to exit, call close() on the StreamConnectionNotifier.
    1. The system removes the service record from the SDDB.
StreamConnectionNotifier and Connector both come from the javax.microedition.io
package of the J2ME platform. The code that accomplishes the above task is shown
below in the following snippet:
 
// lets name our variables
StreamConnectionNotifier notifier = null;
StreamConnection sconn = null;
LocalDevice localdevice = null;
ServiceRecord servicerecord = null;

// step #1
// the String url will already be defined with the 
// correct url parameters
notifier = (StreamConnectionNotifier)Connector.open(url);

// step #2
// we will get the LocalDevice if not already done so
localdevice = LocalDevice.getLocalDevice();
servicerecord = localdevice.getRecord(notifier);

// step #3 is optional

// step #4
// this step will block the current thread until
// a client responds this step will also cause the
// service record to be stored in the SDDB
notifier.acceptAndOpen();

// step #5
// just wait...
// assume the client has connected and you are ready to exit

// step #6
// this causes the service record to be removed 
// from the SDDB
notifier.close();

And that's all that you need to do Service Registration in Bluetooth. The next
step is Communication.
Communication
Bluetooth is a communication protocol, so how do you communicate with it?
Well, the Java Bluetooth API gives you three ways to send and receive data,
but for right now, we'll cover only one of them: RFCOMM.
Note: RFCOMM is the protocol layer that the Serial Port Profile uses in order
to communicate, but these two items are almost always used synonymously.
Server Connections with the Serial Port Profile
The code listing below demonstrates what is needed to open a connection on a Bluetooth
device that will act as a server.
 
// let's name our variables

StreamConnectionNotifier notifier = null;
StreamConnection con = null;
LocalDevice localdevice = null;
ServiceRecord servicerecord = null;
InputStream input;
OutputStream output;

// let's create a URL that contains a UUID that 
// has a very low chance of conflicting with anything
String url = 
  &quot;btspp://localhost:00112233445566778899AABBCCDDEEFF;name=serialconn&quot;;
// let's open the connection with the url and
// cast it into a StreamConnectionNotifier
notifier = (StreamConnectionNotifier)Connector.open(url);

// block the current thread until a client responds
con = notifier.acceptAndOpen();

// the client has responded, so open some streams
input = con.openInputStream();
output = con.openOutputStream();

// now that the streams are open, send and
// receive some data

For the most part, this looks like just about the same code used in Service Registration,
and in fact, it is! Service Registration and Server Communication are both accomplished
using the same lines of code. Here's a few items that I want to point out. The
String url begins with btspp://localhost:, which is
required if you're going to use the Bluetooth Serial Port Profile. Next comes
the UUID part of the URL, which is 00112233445566778899AABBCCDDEEFF.
This is simply a custom UUID that I made up for this service; I could have chosen
any string that was either 32 bits or 128 bits long. Finally, we have ;name=serialconn
in the url String. I could have left off this part, but I want my custom service
to have a name, so the actual service record in the SDDB has the following entry:
ServiceName = serialconn The implementation has also assigned a channel identifier to this service.
The client must provide the channel number along with other parameters in order
to connect to a server.
Client Connections with the Serial Port Profile
Establishing a connection with the Serial Port Profile for a J2ME client is
simple because the paradigm hasn't changed for J2ME I/O. You simply call Connector.open().
StreamConnection con =(StreamConnection)Connector.open(url);
You obtain the url String that is needed to connect to the device from the
ServiceRecord object that you get from Service Discovery. Here's a more
complete listing of code that will show you how a Serial Port Profile client
makes a connection to a Serial Port Profile server.
String connectionURL = serviceRecord.getConnectionURL(0, false);
StreamConnection con =(StreamConnection)Connector.open(connectionURL);
What does a SPP client connection URL look like? If the address of the server
is 0001234567AB, the String that the SPP client would look something like this:
btspp://0001234567AB:3 The 3 at the end of the url String is the channel number that the server assigned
to this service when this service was added to the SDDB.

Java Bluetooth Development Kits

The most widely available development kit for Java Bluetooth applications is
the J2ME
Wireless Toolkit 2.2 from Sun. It incorporates a Bluetooth network simulator,
and has support for OBEX. And best of all, it's free! The current version of
the J2ME Wireless Toolkit is available on Windows platforms.
If you're targeting JSR-82-enabled Nokia phones, such as the 6600, then you
may also want to try out the Nokia
Developer's Suite 2.1. Much like Sun's Wireless Toolkit, the Nokia Developer's
Suite is free and it also includes a Bluetooth network simulator. The Nokia
Developer's Suite supports Windows and Linux platforms.
SonyEricsson also makes a free development kit for its P900 Java Bluetooth-enabled phone, which can be found at their developer site.
Atinav makes one of the most comprehensive JSR-82
implementations and developer kits with support for J2ME CLDC, J2ME CDC,
and J2SE devices. They support numerous RS-232, UART, USB, CF, and PCMCIA Bluetooth
devices. Their solution is based on an all-Java stack, and their SDK includes
the following profiles: GAP, SDAP, SPP, OBEX, FTP, Sync, OPP, Fax, and Printing
-- whew! They make the only JSR-82 implementation for the PocketPC platform,
and also support Windows and Linux.
Possio makes a JSR-82
development kit that complements their Java Bluetooth-enabled access point,
the PX30. The PX30 is a Linux-based access point, and is powered by an Intel XScale
processor. It includes Wi-Fi, Bluetooth, and the CDC Foundation Profile.
Rococo is famous for making the first
Java Bluetooth Simulator, although they also make a Java Bluetooth developer
kit for the Palm OS 4 platform. The simulator is currently priced at $1000, and supports the following profiles:
GAP, SDAP, SPP, and GOEP.
Avetana
is a German company that makes the only JSR-82 implementation for the Mac OS
X platform. They also provide JSR-82 implementations for Windows and Linux.

Summary

What have we learned here? Hopefully, you should have a good understanding
of what Bluetooth is and how to use it. Before you start communicating to other
Bluetooth devices, you need to discover the devices in your vicinity, and search
for their services. After all of the preliminaries are out of the way, you can
stream data back and forth to any Bluetooth-enabled device in your area, whether
it's running Java or not.
With over one million Bluetooth-enabled devices shipping per week (that's
right, one million devices per week), there's a lot of PDAs, cell phones, laptops,
desktops, access points, cameras, keyboards, mice, printers, audio players,
and vehicles out there for your mobile Java apps to play with!

Link:  http://today.java.net/pub/a/today/2004/07/27/bluetooth.html

Tuesday, March 13, 2012

A J2ME Library and a simple HTTP Service Framework

A J2ME Library and a simple HTTP Service Framework

 J2ME's support for calling a server is rather simple and low level. Not only do you have to deal with the HTTP Connection at a low level, there is no high level support for cookies, authentication or remote procedure calling. So if you want to pass an object to the server and get a response, you need to figure out how to do that. XML over HTTP is one solution, but presents its own problems like the serialisation and deserialisation of objects, not to mention higher network traffic because of the meta-data held within the XML. JAX Binding is certainly not supported in J2ME-land which results in you having to use a SAX parser.

In previous projects I have toyed with a simple way of providing services over JSPs, which take and receive delimited text. The idea is to implement your own simple serialization and deserialisation of simple objects allowing you to make simple calls to the server and receive simple responses. I purposefully used the word "simple" four times in that last sentence to impress upon you the idea that server calls should be kept simple.

Take for example a J2ME application which tracks a GPS location. To send the location of the user it can simply send a line of text like this:

    006.574438|045.453345|11022344843373

What's it mean?

    longitude | latitude | timestamp

The serialising and deserialising of the data is VERY simple using a StringTokenizer (erm, which doesn't exist in J2ME, so see later!). And the server could respond with a simply OK or it might want to take the opportunity to update the client with some traffic information:

 M4|4|6|20|Accident

which means:

    road | from junction | to junction | how many minutes delay | reason

Most server calls really can be that simple, especially when being involved in J2ME applications which tend to be relatively simple themselves.

So the above presents a few questions... How secure is the data and how do you know who the update is coming from? Well the data should be sent over SSL to ensure that its secure and if the data is sent over an authenticated session, then the server knows who the logged in user is. But to get a log in and session to work, you need two things, namely cookies (for the session ID to be passed between client and server) and some form of authentication. Cookies in J2ME aren't too easy to handle since there is no built in API for handling them at a high level. You can set a cookie in the request header, but storing cookies from responses is the hard part. I implemented rudimentary cookie handling by sending the response to a method which checks for any set-cookie headers and adds them to the cache as well as cleaning out expired entries. When a request is sent, I call a method which adds all relevant cookies to the request header. I have not implemented the RfC for cookies and don't handle the differences between Cookie and Cookie2. In fact I didn't even go as far as checking the path of the cookie before sending it to the server, because in my environment, it's not even relevant. A proper cookie implementation would need to do those things and more, and perhaps one day, such a library will exist.. I did manage to find this which refers to the JCookie sourceforge project and J2ME, but checking out its site I couldn't find anything that would work with J2ME.

HTTP authentication I originally handled by adding the "authorization" request header and applying a Base64 encoded basic authentication string to it. This caused its own problems, because J2ME doesn't have a Base64 encoder out of the box. Luckily the org.apache.common.codecs.binary.Base64 class works (which I took from the Apache Codecs 1.3 library. It depends upon the following classes which are in the distributable JAR and also J2ME compatible: BinaryDecoder, BinaryEncoder, Decoder, DecoderException, Encoder, EncoderException, all found in the org.apache.commons.codec package.

I ran into a different problem when I wanted my web application for the web site to be the same as the web application for my services. Namely, for services I wanted to use basic authentication and for the web site I wanted to use form login. The servlet spec doesn't let you define more than one login-config per web-app! So the J2ME class I had written for accessing services (ServerCaller) had to be extended, but that wasn't hard. When a web application using Form Login needs you to authenticate, it simply returns the login form instead of the expected response. If you parse the response and check to see if it is your login form, and then simply submit that form with your username and password, the server then logs you in and returns a 302 code telling you to call the original page again. Assuming you provided the correct login credentials, it all works. So my class recursed into itself if it spotted the login form and that was enough to make it work transparently.

The next problem was the parsing of the responses in order to deserialise them. For this I created a very simple StringTokenizer, since neither CLDC nor MIDP gives you one :-( The implementation is below.

URL encoding and decoding is also important because request parameters (for a GET its the request string, for a POST the request body). Luckily there are some options out there. Catalina has one in its util package, which almost works for J2ME. So I did a quick fix to it to remove the dependency on java.util.BitSet which also doesn't exist in J2ME.

So, finally to some code! The magic class is the ServerCaller which you can download below. It is abstract and to use it you simply need to extend it, for example: 

package uk.co.maxant.cam.c;

import java.util.Vector;

import uk.co.maxant.cam.m.MasterData;
import uk.co.maxant.j2me.core.CredentialsProvider;
import uk.co.maxant.j2me.core.ServerCaller;
import uk.co.maxant.j2me.core.StringTokenizer;

/**
 * calls the server to get master data like roles and the version of the latest available download.
 */
public abstract class MasterDataGetter extends ServerCaller implements ServerCaller.Listener {

 private ExceptionHandler eh;
 
 public MasterDataGetter(CredentialsProvider credentialsProvider, ExceptionHandler eh) {
  super(credentialsProvider, Constants.getBaseUrl(), "ota/getMasterData.jsp");
  this.eh = eh;
  setListener(this);
 }
 
 public void callServer(){
  properties.clear();
  properties.put("installUid", String.valueOf(InstallHelper.getInstallationUid(eh)));

  doCallAsync();
 }
 
 protected void handleSuccess(String str) {
  StringTokenizer lines = new StringTokenizer(str, "|");
  String version = lines.nextToken().trim();
  String sessionId = lines.nextToken().trim();
  String screenName = lines.nextToken().trim();
  String roles = lines.nextToken().trim();
  StringTokenizer rs = new StringTokenizer(roles, ",");
  Vector rolesv = new Vector();
  while(rs.hasMoreTokens()){
   rolesv.addElement(rs.nextToken());
  }
  
  String s = lines.nextToken().trim();
  boolean isSendDebugLog = s.equalsIgnoreCase("true");
  
  MasterData masterData = new MasterData(version, rolesv, sessionId, screenName, isSendDebugLog);
  onSuccess(masterData );
 }
 
}

An example of a JSP for the server is:  








 //we know who they are. if the installUid is known, lets add it to their profile!
 String installUid = request.getParameter("installUid");
 if(installUid != null && installUid.equals("null")) installUid = null;

 String auth = request.getHeader("authorization");

 OrchestrationService os = ServiceLocator.getInstance().getOrchestrationService();
 MasterData md = os.getMasterData(auth, installUid);
 if(md.party != null) user = md.party.getScreenname();
 for(String role : md.roles){
  roles += role + ",";
 }
 String version = VersionHelper.getVersionFromJad(request);
 
 boolean sendDebugLog = true; //change to false if we get swamped. but really, we shouldnt ever get this stuff.
 
 %>OK
 <%=version%>|
 <%=session.getId()%>|
 <%=user%>|
 <%=roles%>|
 <%=sendDebugLog%>|
 <%
}catch(Exception e){
 log.warn("failed to read master data", e);
 %>ERROR
 <%=e.getMessage() %>
 <%
}
%>
The result, is the maxant J2ME library, which runs on CLDC 1.1 and MIDP 2.0, and can be downloaded here. It includes classes for all of the following, and more, and is released under the LGPL Licence:


  • URLEncoder - from Apache Catalina
  • Base64 - from Apache Commons Codec
  • CredentialsProvider - an interface which the ServerCaller uses to get server credentials for logging in
  • Formatter - formats for example decimals nicely
  • GAUploader - loads an event to Google Analytics
  • Math - some math stuff thats not in CLDC
  • Point - a 2 dimensional point in a plane
  • ServerCaller - a high level API for calling a server, as described above
  • StringTokenizer - simple, and a lot like that from J2SE
  • URL - an encapsulation of a protocol, domain, port and page
  • ImageHelper - code taken from the web for scaling images
  • DirectoryChooser - a UI for choosing a local directory on the device
  • FileChooser - a UI for choosing a local file on the device


To use the library, add it to the "lib" folder of your J2ME project, then ensure its on the build path, and in Eclipse Pulsar, you need to also check the box in the build path on the last tab, to ensure the classes in the JAR are exported to your JADs JAR.

Link: http://blog.maxant.co.uk/pebble/2010/02/21/1266791340000.html

Monday, March 5, 2012

J2ME - Search Service Bluetooth

J2ME - Search Service Bluetooth

// Example Search Service Bluetooth
import java.util.Vector;

import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;
import javax.bluetooth.UUID;

public class ClientChat implements DiscoveryListener
{
        private static final String CHATTANDO_UUID = "A1A2A3A4A5A6A7A8A9A0B1B2B3B4B5B6";
        private static final String CHATTANDO_SERVICE = "Chattando";

        protected Chattando midlet;
       
        private boolean searchDone = false;
       
        private DiscoveryAgent discovery_agent;
       
        private Vector remote_device;
        private Vector device_found;
       
        public ClientChat(Chattando midlet)
        {
               this.midlet = midlet;
              
               startScanBluetoothDevices();
        }
       
        // Avvia la ricerca dei dispositivi Bluetooth
        public void startScanBluetoothDevices()
        {
               try
               {
                       remote_device = new Vector();
                       device_found = new Vector();
                      
                       discovery_agent = LocalDevice.getLocalDevice().getDiscoveryAgent();
                       discovery_agent.startInquiry(DiscoveryAgent.GIAC, this);
}
               catch(Exception error)
               {
                       error.printStackTrace();
               }
        }
// Stoppa la ricerca dei dispositivi Bluetooth
        public void stopScanBluetoothDevices()
        {
               discovery_agent.cancelInquiry(this); 
        }

        public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod)
        { 
 // Aggiungo il dispositivo solo se e' un computer (0x0100) o un cellulare (0x0200) 
 if(cod.getMajorDeviceClass() == 0x0100 || cod.getMajorDeviceClass() == 0x0200)remote_device.addElement(btDevice);
        }
public void inquiryCompleted(int discType)
        {
               switch(discType)
               {
                       case DiscoveryListener.INQUIRY_COMPLETED:
                                                                                                     System.out.println("Device Search Completed");
                                                                                                     
                                                                                                     break;
                              
                       case DiscoveryListener.INQUIRY_ERROR:
                                                                                                     System.out.println("Device Search Error");
                                                                                                    
                                                                                                     break;
                              
                       case DiscoveryListener.INQUIRY_TERMINATED:
                                                                                                     System.out.println("Device Search Terminated");
                                                                                                    
                                                                                                     break;
               }
              
               try
               {
                       for(int i=0, cnt=remote_device.size(); i<cnt; i++)
                       {
                               discovery_agent.searchServices(new int[]{ 0x0100, 0x0200 }, new UUID[]{ new UUID(0x0003), new UUID(CHATTANDO_UUID, false) }, (RemoteDevice) remote_device.elementAt(i), this);
                               waitForSearchDone();
                       }
               }
               catch(Exception error)
               {
                       error.printStackTrace();
               }
        }

        // Aspetta che la ricerca dei servizi per il dispositivo sia terminata
        private void waitForSearchDone()
        {
               searchDone = false;
              
               try
               {
                       while(!searchDone)
                       {
                               synchronized(this)
                               {
                                      this.wait();
                               }
                       }
               }
               catch(Exception error)
               {
                      
               }
        }
       
        public void serviceSearchCompleted(int transID, int respCode)
        {
               switch(respCode)
               {
                       case DiscoveryListener.SERVICE_SEARCH_COMPLETED:
System.out.println("Service Search Completed");
break;                case 

DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE: 
System.out.println("Service Search Device not Reachable");
break;
case DiscoveryListener.SERVICE_SEARCH_ERROR:
                                                                                              System.out.println("Service Search Error");
break;
case DiscoveryListener.SERVICE_SEARCH_NO_RECORDS:
System.out.println("Service Search No Records");
break;
case DiscoveryListener.SERVICE_SEARCH_TERMINATED:                                                                                           System.out.println("Service Search Terminated")
break;
               }
searchDone = true;

// Risveglia il processo in attesa del completamento della ricerca dei servizi per un dispositivo 
 synchronized(this)
  {
      this.notifyAll();
      }
  }
public void servicesDiscovered(int transID, ServiceRecord[] servRecord)
 {
               for(int i=0, cnt=servRecord.length; i<cnt; i++)
               {
                if(((String)
servRecord[i].getAttributeValue(0x0100).getValue()).equalsIgnoreCase
(CHATTANDO_SERVICE))
                       {
                        device_found.addElement(servRecord[i].getHostDevice());
                       }
               }
        }
}