Using the following code you can start bluetooth connection in your
mobile. This will register the service(UUID) while starting the
bluetooth
connection. You can find the active bluetooth devices near
to your mobile which has registered same service(UUID) and you can
connect with them.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import java.io.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import javax.bluetooth.*;
import java.util.*;
/**
* @author test
*/
public class Blue extends MIDlet implements CommandListener,DiscoveryListener {
private List activeDevices;
private List activeServices;
private Command select,exit;
private Display display;
private LocalDevice local=null;
private DiscoveryAgent agent = null;
private Vector devicesFound = null;
private ServiceRecord[] servicesFound = null;
private String connectionURL = null;
public void startApp() {
display = Display.getDisplay(this);
activeDevices
= new List("Active Devices", List.IMPLICIT);
activeServices
= new List("Active Services", List.IMPLICIT);
select = new Command("Select", Command.OK, 0);
exit = new Command("Exit", Command.EXIT, 0);
activeDevices.addCommand(exit);
activeServices.addCommand(exit);
activeDevices.setCommandListener(this);
activeServices.setCommandListener(this);
try {
local
= LocalDevice.getLocalDevice();
} catch (Exception e) {
}
doDeviceDiscovery();
display.setCurrent(activeDevices);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
notifyDestroyed();
}
public void commandAction(Command cmd, Displayable disp) {
if (cmd == select && disp == activeDevices) {
int
device = activeDevices.getSelectedIndex();
doServiceSearch((RemoteDevice)
devicesFound.elementAt(device));
display.setCurrent(activeServices);
//doServiceSearch(
(RemoteDevice)devicesFound.firstElement());
}
if (cmd == select && disp == activeServices) {
int
service = activeServices.getSelectedIndex();
connectionURL
= servicesFound[service].getConnectionURL(0, false);
try {
StreamConnection
sc = (StreamConnection) Connector.open(connectionURL);
OutputStream
outStream = connection.openOutputStream();
PrintWriter
pWriter = new PrintWriter(new OutputStreamWriter(outStream));
pWriter.write("Response
String from SPP Server\r\n");
pWriter.flush();
pWriter.close();
}
catch (Exception e) {
Alert
alert = new Alert("");
alert.setString(e.toString());
display.setCurrent(alert);
}
}
if (cmd == exit) {
destroyApp(false);
}
}
public void inquiryCompleted(int param) {
switch (param) {
case
DiscoveryListener.INQUIRY_COMPLETED:
/*
Inquiry completed normally, add appropriate code
* here
*/
if
(devicesFound.size() > 0) {
activeDevices.addCommand(select);
activeDevices.setSelectCommand(select);
}
else {
try
{
activeDevices.append("No
Devices Found", null);
startServer();
}
catch (Exception e) {
}
}
break;
case
DiscoveryListener.INQUIRY_ERROR:
//
Error during inquiry, add appropriate code here.
break;
case
DiscoveryListener.INQUIRY_TERMINATED:
/*
Inquiry terminated by agent.cancelInquiry()
*
Add appropriate code here.
*/
break;
}
}
public void serviceSearchCompleted(int transID, int respCode) {
switch (respCode) {
case
DiscoveryListener.SERVICE_SEARCH_COMPLETED:
break;
case
DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE:
break;
case
DiscoveryListener.SERVICE_SEARCH_ERROR:
break;
case
DiscoveryListener.SERVICE_SEARCH_NO_RECORDS:
break;
case
DiscoveryListener.SERVICE_SEARCH_TERMINATED:
break;
}
}
public void servicesDiscovered(int transID, ServiceRecord[] serviceRecord) {
servicesFound = serviceRecord;
activeServices.append(servicesFound.toString(), null);
activeServices.addCommand(select);
activeServices.setSelectCommand(select);
}
public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass deviceClass) {
String str = null;
try {
str
= remoteDevice.getFriendlyName(true);
} catch (Exception e) {
}
activeDevices.append(str, null);
devicesFound.addElement(remoteDevice);
}
private void doDeviceDiscovery() {
try {
local
= LocalDevice.getLocalDevice();
} catch (BluetoothStateException bse) {
// Error handling code here
}
agent = local.getDiscoveryAgent();
devicesFound = new Vector();
try {
if
(!agent.startInquiry(DiscoveryAgent.GIAC, this)) {
//
Inquiry not started, error handling code here
}
} catch (BluetoothStateException bse) {
//
Error handling code here
}
}
private void doServiceSearch(RemoteDevice device) {
int[] attributes = {0x100, 0x101, 0x102};
UUID[] uuids = new UUID[1];
uuids[0] = new UUID("1101", false);
try {
agent.searchServices(attributes,
uuids, device, this);
} catch (BluetoothStateException e) {
Alert
alert1 = new Alert("Error");
alert1.setString(e.toString());
display.setCurrent(alert1);
}
}
public void startServer() throws IOException {
UUID uuid = new UUID("1101", false);
//Create the service url
String
connectionString = "btspp://localhost:" + uuid + ";name=xyz";
//open server url
StreamConnectionNotifier
streamConnNotifier = (StreamConnectionNotifier)
Connector.open(connectionString);
//Wait for client connection
System.out.println("\nServer
Started. Waiting for clients to connect...");
StreamConnection
connection = streamConnNotifier.acceptAndOpen();
RemoteDevice
dev = RemoteDevice.getRemoteDevice(connection);
System.out.println("Remote
device address: " + dev.getBluetoothAddress());
System.out.println("Remote
device name: " + dev.getFriendlyName(true));
//read string from spp client
try {
DataInputStream
in = (DataInputStream) connection.openDataInputStream();
/*BufferedReader
bReader=new BufferedReader(new InputStreamReader(inStream));
String
lineRead=bReader.readLine();
System.out.println(lineRead);*/
/*//send
response to spp client
OutputStream
outStream=connection.openOutputStream();
PrintWriter
pWriter=new PrintWriter(new OutputStreamWriter(outStream));
pWriter.write("Response
String from SPP Server\r\n");
pWriter.flush();
pWriter.close();*/
streamConnNotifier.close();
}
}
Link: http://j2mesamples.blogspot.com/2009/02/how-to-find-active-bluetooth-devices.html
Tuesday, June 12, 2012
Sunday, June 10, 2012
How to connect and retrieve NMEA sentences from bluetooth GPS
To connect/retrieve NMEA sentences from bluetooth GPS, your program needs to do the following tasks:
1. inquiry bluetooth device in range.
2. get bluetooth friendly name
3. select bluetooth GPS receiver from the list of detected devices.
4. search for service provided by GPS device.
4. get connection string from GPS device.
5. connect to and receive sentences from GPS device.
Bluetooth GPS receiver provides L2CAP service, so your program needs to search for this service in order to get GPS’s connection string url
private UUID[] uuidSet;
private UUID L2CAP_UUID = new UUID(0×0100); // L2CAP service
uuidSet = new UUID[1];
uuidSet[0] = L2CAP_UUID;
We need a ChoiceGroup to store a list of bluetooth friendly name of detected devices. We also need a vector to store detected devices.
ChoiceGroup labels;
Vector remoteDevices = new Vector();
LocalDevice localDevice;
DiscoveryAgent discoveryAgent;
Here is the sample code to inquiry bluetooth device in range:
public void inquiryDevice()
{
inquiryCompleted = false;
try
{
localDevice = LocalDevice.getLocalDevice();
discoveryAgent = localDevice.getDiscoveryAgent();
// inquiry bluetooth device in range
// each time when a bluetooth device is discovered, DiscoveryListener will trigger procedure deviceDiscovered.
// when inquiry completed, DiscoveryListener will trigger procedure inquiryCompleted
discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this);
}
catch (Exception e)
{
}
}
public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod)
{
try
{
labels.append(btDevice.getFriendlyName(false), null); // we need to remember bluetooth friendly name of detected device.
remoteDevices.addElement(btDevice); // we also need to remember detected device by adding it to a vector list.
numDevice++; // increase number of detected device by 1
}
catch (Exception e)
{
}
}
public void inquiryCompleted(int discType)
{
inquiryCompleted = true;
}
After inquiry bluetooth device completed, we have a vector list that contain all the detected devices (remoteDevices) and a list of bluetooth friendly names (lables). Our program need to display the list of bluetooth friendly names and let user select one of them.
When user selected one bluetooth friendly name from the list of bluetooth friendly names (lables) we will have the selected index (id). Pass this index (id) as a parameter to procedure startServiceSearch. Procedure startServiceSearch will get the element that has the same index with the selected index from the vector of detected devices (remoteDevices). Then we search for L2CAP service from selected device.
Here is the sample code to search for L2CAP service:
public void startServiceSearch(int id)
{
serviceSearchCompleted = false;
try
{
// Search for Services
remoteDevice = (RemoteDevice)remoteDevices.elementAt(id);
// when a service is discovered, DiscoverLinstener will trigger procedure servicesDiscovered
// when service search completed, DiscoverLinstener will trigger procedure serviceSearchCompleted
int searchID = discoveryAgent.searchServices(null,uuidSet,remoteDevice,this);
}
catch (Exception e)
{
}
}
public void servicesDiscovered(int transID, ServiceRecord[] servRecord)
{
for(int i=0; i < servRecord.length; i++)
{
serviceUrl = servRecord[i].getConnectionURL(0,false); // when a service is discovered, we need to store connection url for later use. GPS receiver provides only one service.
}
}
public void serviceSearchCompleted(int transID, int responseCode)
{
serviceSearchCompleted = true;
}
After search service completed you will have serviceUrl. This is GPS’s connection string. We will use this connection string to connect to GPS receiver.
Now we connect and retrieve data from bluetooth GPS receiver.
private StreamConnection connection = null;
private InputStream reader = null;
// open connection to GPS
try
{
if (connection == null)
connection = (StreamConnection)Connector.open(serviceUrl); // how to get this serviceUrl has been discussed in above post
if (reader == null)
reader = connection.openInputStream();
}
catch (IOException e) {}
// when the connection is opened and ready, GPS will continueously send NMEA sentences by writing to OutputStream of the bluetooth connection.
// our program need to continueously read data from InputStream of the bluetooth connection. The speed of reading in our program need to be same or faster than the speed of writing otherwise the stream will be overflow.
byte data[];
int byteCount;
string buffer;
string sentence;
while (your stop condition)
{
data = new byte[512];
try
{
byteCount = reader.read(data); // we read all data in InputStream
if (byteCount == -1) // no data from inputStream
{
sentence = null;
return;
}
buffer = new String(data,0,byteCount); // convert byte array data to string
// parse NMEA sentence, I will explain later
if (buffer.indexOf(”$GPRMC”) > -1)
{
sentence = buffer.substring(buffer.indexOf(”$GPRMC”));
if (sentence.indexOf(”*”) > -1)
sentence = sentence.substring(0,sentence.indexOf(”*”));
else
{
if (buffer.indexOf(”$GPGGA”) > -1)
{
sentence = buffer.substring(buffer.indexOf(”$GPGGA”));
if (sentence.indexOf(”*”) > -1)
sentence = sentence.substring(0,sentence.indexOf(”*”));
else
sentence = null;
}
}
}
else
{
if (buffer.indexOf(”$GPGGA”) > -1)
{
sentence = buffer.substring(buffer.indexOf(”$GPGGA”));
if (sentence.indexOf(”*”) > -1)
sentence = sentence.substring(0,sentence.indexOf(”*”));
else
sentence = null;
}
else
sentence = null;
}
}
catch (IOException e)
{
sentence = e.getMessage();
}
} // end of while (your stop condition)
// close GPS connection
try
{
if (reader != null)
reader.close();
if (connection != null)
connection.close();
reader = null;
connection = null;
}
catch (IOException e)
{
reader = null;
connection = null;
}
String output;
int input;
while ((input = reader.read()) != 13)
output += (char) input;
or
String output;
int input;
input = reader.read();
while (input != -1)
{
output += (char) input;
input = reader.read();
}
You will notice that the code above read one by one character from bluetooth GPS receiver until character 13 or no data was return. If you follow this way, overflow can be happend very
easily because the bluetooth GPS receiver keep sending data continously and your program was not fast enough to read from inputStream.
I use different approach to read NMEA sentence. My approach is based on my observing on how bluetooth GPS receiver behaviour:
1. bluetooth GPS receiver keep sending data continously so I use a byte array 512 bytes to read and store all data at specific of time instead of reading one by one character.
2. bluetooth GPS receiver send a lot of NMEA sentence types but my program need only $GPRMC and $GPGGA sentence type, so I ignore all other sentence types.
3. sentence type $GPRMC contains lat/lon and velocity information while sentence type $GPGGA contains only lat/lon, so I give sentence type $GPRMC more priority than sentence type $GPGGA.
4. each sentence start with “$” and end with “*”
Here is the logic of my approach:
5. Repeat step 1 to step 4 again.
By using this approach, your program will get the latest lat/lon and/or velocity information (ignore other sentence types)
Link: http://www.digitalmobilemap.com/how-to-connect-and-retrieve-nmea-sentences-from-bluetooth-gps
1. inquiry bluetooth device in range.
2. get bluetooth friendly name
3. select bluetooth GPS receiver from the list of detected devices.
4. search for service provided by GPS device.
4. get connection string from GPS device.
5. connect to and receive sentences from GPS device.
Bluetooth GPS receiver provides L2CAP service, so your program needs to search for this service in order to get GPS’s connection string url
private UUID[] uuidSet;
private UUID L2CAP_UUID = new UUID(0×0100); // L2CAP service
uuidSet = new UUID[1];
uuidSet[0] = L2CAP_UUID;
We need a ChoiceGroup to store a list of bluetooth friendly name of detected devices. We also need a vector to store detected devices.
ChoiceGroup labels;
Vector remoteDevices = new Vector();
LocalDevice localDevice;
DiscoveryAgent discoveryAgent;
Here is the sample code to inquiry bluetooth device in range:
public void inquiryDevice()
{
inquiryCompleted = false;
try
{
localDevice = LocalDevice.getLocalDevice();
discoveryAgent = localDevice.getDiscoveryAgent();
// inquiry bluetooth device in range
// each time when a bluetooth device is discovered, DiscoveryListener will trigger procedure deviceDiscovered.
// when inquiry completed, DiscoveryListener will trigger procedure inquiryCompleted
discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this);
}
catch (Exception e)
{
}
}
public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod)
{
try
{
labels.append(btDevice.getFriendlyName(false), null); // we need to remember bluetooth friendly name of detected device.
remoteDevices.addElement(btDevice); // we also need to remember detected device by adding it to a vector list.
numDevice++; // increase number of detected device by 1
}
catch (Exception e)
{
}
}
public void inquiryCompleted(int discType)
{
inquiryCompleted = true;
}
After inquiry bluetooth device completed, we have a vector list that contain all the detected devices (remoteDevices) and a list of bluetooth friendly names (lables). Our program need to display the list of bluetooth friendly names and let user select one of them.
When user selected one bluetooth friendly name from the list of bluetooth friendly names (lables) we will have the selected index (id). Pass this index (id) as a parameter to procedure startServiceSearch. Procedure startServiceSearch will get the element that has the same index with the selected index from the vector of detected devices (remoteDevices). Then we search for L2CAP service from selected device.
Here is the sample code to search for L2CAP service:
public void startServiceSearch(int id)
{
serviceSearchCompleted = false;
try
{
// Search for Services
remoteDevice = (RemoteDevice)remoteDevices.elementAt(id);
// when a service is discovered, DiscoverLinstener will trigger procedure servicesDiscovered
// when service search completed, DiscoverLinstener will trigger procedure serviceSearchCompleted
int searchID = discoveryAgent.searchServices(null,uuidSet,remoteDevice,this);
}
catch (Exception e)
{
}
}
public void servicesDiscovered(int transID, ServiceRecord[] servRecord)
{
for(int i=0; i < servRecord.length; i++)
{
serviceUrl = servRecord[i].getConnectionURL(0,false); // when a service is discovered, we need to store connection url for later use. GPS receiver provides only one service.
}
}
public void serviceSearchCompleted(int transID, int responseCode)
{
serviceSearchCompleted = true;
}
After search service completed you will have serviceUrl. This is GPS’s connection string. We will use this connection string to connect to GPS receiver.
Now we connect and retrieve data from bluetooth GPS receiver.
private StreamConnection connection = null;
private InputStream reader = null;
// open connection to GPS
try
{
if (connection == null)
connection = (StreamConnection)Connector.open(serviceUrl); // how to get this serviceUrl has been discussed in above post
if (reader == null)
reader = connection.openInputStream();
}
catch (IOException e) {}
// when the connection is opened and ready, GPS will continueously send NMEA sentences by writing to OutputStream of the bluetooth connection.
// our program need to continueously read data from InputStream of the bluetooth connection. The speed of reading in our program need to be same or faster than the speed of writing otherwise the stream will be overflow.
byte data[];
int byteCount;
string buffer;
string sentence;
while (your stop condition)
{
data = new byte[512];
try
{
byteCount = reader.read(data); // we read all data in InputStream
if (byteCount == -1) // no data from inputStream
{
sentence = null;
return;
}
buffer = new String(data,0,byteCount); // convert byte array data to string
// parse NMEA sentence, I will explain later
if (buffer.indexOf(”$GPRMC”) > -1)
{
sentence = buffer.substring(buffer.indexOf(”$GPRMC”));
if (sentence.indexOf(”*”) > -1)
sentence = sentence.substring(0,sentence.indexOf(”*”));
else
{
if (buffer.indexOf(”$GPGGA”) > -1)
{
sentence = buffer.substring(buffer.indexOf(”$GPGGA”));
if (sentence.indexOf(”*”) > -1)
sentence = sentence.substring(0,sentence.indexOf(”*”));
else
sentence = null;
}
}
}
else
{
if (buffer.indexOf(”$GPGGA”) > -1)
{
sentence = buffer.substring(buffer.indexOf(”$GPGGA”));
if (sentence.indexOf(”*”) > -1)
sentence = sentence.substring(0,sentence.indexOf(”*”));
else
sentence = null;
}
else
sentence = null;
}
}
catch (IOException e)
{
sentence = e.getMessage();
}
} // end of while (your stop condition)
// close GPS connection
try
{
if (reader != null)
reader.close();
if (connection != null)
connection.close();
reader = null;
connection = null;
}
catch (IOException e)
{
reader = null;
connection = null;
}
Let me explain the logic of reading NMEA sentence.
If you search the internet on how to read NMEA sentence from a
bluetooth GPS receiver, ussually you will get the answer similar to
this:String output;
int input;
while ((input = reader.read()) != 13)
output += (char) input;
or
String output;
int input;
input = reader.read();
while (input != -1)
{
output += (char) input;
input = reader.read();
}
You will notice that the code above read one by one character from bluetooth GPS receiver until character 13 or no data was return. If you follow this way, overflow can be happend very
easily because the bluetooth GPS receiver keep sending data continously and your program was not fast enough to read from inputStream.
I use different approach to read NMEA sentence. My approach is based on my observing on how bluetooth GPS receiver behaviour:
1. bluetooth GPS receiver keep sending data continously so I use a byte array 512 bytes to read and store all data at specific of time instead of reading one by one character.
2. bluetooth GPS receiver send a lot of NMEA sentence types but my program need only $GPRMC and $GPGGA sentence type, so I ignore all other sentence types.
3. sentence type $GPRMC contains lat/lon and velocity information while sentence type $GPGGA contains only lat/lon, so I give sentence type $GPRMC more priority than sentence type $GPGGA.
4. each sentence start with “$” and end with “*”
Here is the logic of my approach:
1. Read all data from bluetooth GPS receiver at the same time.
2. If $GPRMC is found then get the substring from $GPRMC until first occurence of ‘*’ after $GPRMC
3. If $GPRMC is not found then search for $GPGGA. If $GPGGA is found
then get the substring from $GPGGA until first occurence of ‘*’ after
$GPGGA
4. If 2 and 3 are not found then return invalid sentence (ignore these data)
5. Repeat step 1 to step 4 again.
By using this approach, your program will get the latest lat/lon and/or velocity information (ignore other sentence types)
Link: http://www.digitalmobilemap.com/how-to-connect-and-retrieve-nmea-sentences-from-bluetooth-gps
How to search for Bluetooth devices and services
To use the Bluetooth protocol on Java ME application your mobile device must implement the JSR 82 Bluetooth API.
One of the main challenges on Bluetooth applications is to find out the connection address, for devices with specific services available on them.
In the following sample we are going to see how to implement this code using a class called BtManager.
Let's start creating the class and some variables to store our results.
As you can see we are going to implement the DiscoveryListener interface. This interface provides all the callbacks for our bluetooth calls. Let's start for searching for devices:
Now that we have a list of devices, let's search for the services we want:
After we got all the data stored in our Vectors, we just need to add two methods to retrieve information, one to retrieve the Bluetooth Url and another Bluetooth user friendly name, after all Bluetooth urls, don't have a lot of meaning to the end users of our application.
And with those last methods we completed our Bluetooth finder class. You can check the full source code where I provide a example of how to use it to search for Bluetooth GPS.
Link: http://www.developer.nokia.com/Community/Wiki/How_to_search_for_Bluetooth_devices_and_services
In the following sample we are going to see how to implement this code using a class called BtManager.
Let's start creating the class and some variables to store our results.
import java.util.Vector; // bluetooth classes 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 BTManager implements DiscoveryListener { // used to store devices we found public Vector btDevicesFound; // used to store service information for each device public Vector btServicesFound; public BTManager() { btDevicesFound = new Vector(); btServicesFound = new Vector(); } public int find(UUID[] aServices){ // search for devices findDevices(); // search for services in the devices found findServices(aServices); return btDevicesFound.size(); }
As you can see we are going to implement the DiscoveryListener interface. This interface provides all the callbacks for our bluetooth calls. Let's start for searching for devices:
public int findDevices() { try { // cleans previous elements btDevicesFound.removeAllElements(); // resets status variable isBTSearchComplete = false; LocalDevice local = LocalDevice.getLocalDevice(); DiscoveryAgent discoveryAgent = local.getDiscoveryAgent(); // start discovery of new devices discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this); while ((!isBTSearchComplete)) { //waits for a fixed time, to avoid long search synchronized (this) { this.wait(BTManager.BLUETOOTH_TIMEOUT); } // check if search is completed if (!isBTSearchComplete) { // search no yet completed so let's cancel it discoveryAgent.cancelInquiry(this); } } } catch (Exception e) { e.printStackTrace(); } // returns the number of devices found return btDevicesFound.size(); } public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass deviceClass) { btDevicesFound.addElement(remoteDevice); } public void inquiryCompleted(int param) { isBTSearchComplete = true; // notifies and wake main thread that device search is completed synchronized (this) { this.notify(); } }
Now that we have a list of devices, let's search for the services we want:
public void findServices(UUID[] aServices) { // cleans previous elements btServicesFound.removeAllElements(); try { LocalDevice local = LocalDevice.getLocalDevice(); DiscoveryAgent discoveryAgent = local.getDiscoveryAgent(); // discover services if (btDevicesFound.size() > 0) { for (int i = 0; i < btDevicesFound.size(); i++) { isBTSearchComplete = false; // adds a null element in case we don't found service btServicesFound.addElement(null); int transID = discoveryAgent.searchServices(null, aServices, (RemoteDevice) (btDevicesFound.elementAt(i)), this); // wait for service discovery ends synchronized (this) { this.wait(BTManager.BLUETOOTH_TIMEOUT); } if (!isBTSearchComplete) { discoveryAgent.cancelServiceSearch(transID); } } } } catch (Exception e) { e.printStackTrace(); } } public void servicesDiscovered(int param, ServiceRecord[] serviceRecord) { int index = btServicesFound.size() - 1; for (int i = 0; i < serviceRecord.length; i++) { btServicesFound.setElementAt(serviceRecord[i], index); } } public void serviceSearchCompleted(int transID, int respCode) { isBTSearchComplete = true; // notifies and wake mains thread that service search is completed synchronized (this) { this.notify(); } }
After we got all the data stored in our Vectors, we just need to add two methods to retrieve information, one to retrieve the Bluetooth Url and another Bluetooth user friendly name, after all Bluetooth urls, don't have a lot of meaning to the end users of our application.
public String getDeviceName(int deviceID) { try { return ((RemoteDevice) btDevicesFound.elementAt(deviceID)) .getFriendlyName(false); } catch (Exception e) { e.printStackTrace(); } return "Error"; } public String getServiceURL(int deviceID) { try { return ((ServiceRecord) btServicesFound.elementAt(deviceID)) .getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false); } catch (Exception e) { e.printStackTrace(); } return "Error"; }
And with those last methods we completed our Bluetooth finder class. You can check the full source code where I provide a example of how to use it to search for Bluetooth GPS.
Link: http://www.developer.nokia.com/Community/Wiki/How_to_search_for_Bluetooth_devices_and_services
Wednesday, June 6, 2012
How to read Location from Bluetooth GPS
One of the most sold accessories for mobile phones and PDAs are
Bluetooth GPS (BT-GPS). These simple devices connect to the GPS
satellite system and allows to pinpoint your position with 5 meters
precision. It's possible to access this information trough a JavaME
application you just need to have Bluetooth phone with the Java APIs
available on it.
To read location information from a bluetooth GPS, we need to implement the following tasks:
For the purpose of reading data from the BT-GPS lets create an GpsBt class. The first thing to do is to create some variable to store the URL address for your BT-GPS.
As you may have noticed I'm implementing the reading loop using a thread. The reason for this, is that the BT-GPS is always sending data so you need to keep read from it before the connection buffer overflows. The data the BT-GPS sends are NMEA sentences, these sentences gives several information about the GPS status. The one we are searching for is the GPGGA sentence that gives essential fix data and provides 3D location and accuracy data.
After we have the correct sentence we just need to parse the information and retrieve it to the user
To help us to retrieve data we use a class, called Location, to parse the GGA sentence and wrap the position data. We are also using a class called StringTokenizer to split the tokens in the sentence.
And that's a wrap we now have a class capable of reading the NMEA sentences from the BT-GPS and retrieve location info. Check the full source code for an complete application that allows you to search for devices, connect to them and shows the location info on the screen.
Link:http://www.developer.nokia.com/Community/Wiki/How_to_read_Location_from_Bluetooth_GPS
JSR 179 - Location API
In devices where JSR 179 - Location API is implemented, there's no need to directly use JSR 82 (Bluetooth API) to read location data, since the Location API does all the necessary work for retrieval of the location data itself:- Searching the GPS module in the BT local area
- Pairing with GPS device
- Retrieval of positioning data
- Parsing of low-level NMEA sentences, turning them into high-level Java objects.
JSR 82 - Bluetooth API
If your device does not implement JSR 179, you'll still be able to retrieve location data from a Bluetooth GPS module, but you'll have to do it manually. For that, you need to perform the following tasks:To read location information from a bluetooth GPS, we need to implement the following tasks:
- Search for the Bluetooth GPS device
- Connect to the GPS device
- Read and Parse NMEA sentences
For the purpose of reading data from the BT-GPS lets create an GpsBt class. The first thing to do is to create some variable to store the URL address for your BT-GPS.
// current bluetooth device public String btUrl = ""; public String btName = ""; public void setDevice(String btUrl, String btName) { this.btUrl = btUrl; this.btName = btName; }Now we need to connect to the device and start reading the data.
public void start() { if (isActive) { stop(); } connect(); if (isConnected) { isActive = true; Thread t = new Thread(this); t.start(); } } public void connect() { if (btUrl == null || (btUrl.trim().compareTo("") == 0)) { isConnected = false; return; } try { conn = (StreamConnection) Connector.open(btUrl, Connector.READ_WRITE); in = new DataInputStream(conn.openInputStream()); isConnected = true; mode = 0; } catch (IOException e) { close(); } } public void run() { isActive = true; while (isActive) { // check if connection is still open if (!isConnected && isActive) { // connect to gps device connect(); } else { // read NMEA Strings readNMEASentences(); } } close(); isActive = false; }
As you may have noticed I'm implementing the reading loop using a thread. The reason for this, is that the BT-GPS is always sending data so you need to keep read from it before the connection buffer overflows. The data the BT-GPS sends are NMEA sentences, these sentences gives several information about the GPS status. The one we are searching for is the GPGGA sentence that gives essential fix data and provides 3D location and accuracy data.
public void readNMEASentences() { try { if (!isConnected) { return; } // check characters available int size = in.available(); if (size <= 0) { return; } // read data for (int j = 0; j < size; j++) { int i = in.read(); if (i != -1) { char l = (char) i; switch (mode) { case (STATE_SEARCH_SENTENCE_BEGIN): { // search for the sentence begin if (l == '$') { // found begin of sentence mode = 1; sb.setLength(0); } } break; case (STATE_READ_DATA_TYPE): { // check what kind of sentence we have sb.append(l); if (sb.length() == 6) { if (sb.toString().startsWith("GPGGA")) { mode = STATE_READ_SENTENCE; sb.setLength(0); } else { mode = STATE_SEARCH_SENTENCE_BEGIN; sb.setLength(0); } } } break; case (STATE_READ_SENTENCE): { // read data from sentence sb.append(l); if ((l == 13) || (l == 10) || (l == '$')) { mode = STATE_SEARCH_SENTENCE_BEGIN; currentInfo = new String(sb.toString()); } } break; } } else { close(); } } } catch (Exception e) { close(); } }
After we have the correct sentence we just need to parse the information and retrieve it to the user
public Location getLocation() { Location location = new Location(); if (isConnected && isActive && currentInfo != null) { location.parseGPGGA(currentInfo); } return location; }
To help us to retrieve data we use a class, called Location, to parse the GGA sentence and wrap the position data. We are also using a class called StringTokenizer to split the tokens in the sentence.
public class Location { // NMEA GPGGA Elements String utc; String latitude; String northHemi; String longitude; String eastHemi; String altitude; int quality; int nSat; String horDilution; String altitudeUnit; String geoidalHeight; String geoidalHeightUnit; String diffCorrection; String diffStationId; /** * Method that parses a NMEA string and returns Location. For more info check * this page: http://www.gpsinformation.org/dale/nmea.htm#GGA * * @param value - * string that represent NMEA GGA string */ public void parseGPGGA(String value) { // Helper class to parse strings StringTokenizer tok = new StringTokenizer(value, ","); utc = tok.nextToken(); latitude = tok.nextToken(); northHemi = tok.nextToken(); longitude = tok.nextToken(); eastHemi = tok.nextToken(); quality = Integer.parseInt(tok.nextToken()); nSat = Integer.parseInt(tok.nextToken()); horDilution = tok.nextToken(); altitude = tok.nextToken(); altitudeUnit = tok.nextToken(); geoidalHeight = tok.nextToken(); geoidalHeightUnit = tok.nextToken(); diffCorrection = tok.nextToken(); diffStationId = tok.nextToken(); } }
And that's a wrap we now have a class capable of reading the NMEA sentences from the BT-GPS and retrieve location info. Check the full source code for an complete application that allows you to search for devices, connect to them and shows the location info on the screen.
Link:http://www.developer.nokia.com/Community/Wiki/How_to_read_Location_from_Bluetooth_GPS
Sunday, June 3, 2012
How to Test Java Games on Your Computer
The amount of users with
mobile phones has made them a lucrative market for gaming companies, and
there are a wealth of games available for these devices. Due to the
large amount of different phones and games on offer it can be hard to
make a choice as to what to purchase. With a mobile emulator, Java games
or demos can be played in order to determine if they will be compatible
with your phone or if the game style is suited to your taste.
Instructions
-
-
1
Navigate to the Mpowerplayer website and click the
"Download now" link (see Resource 1). A pop-up window with the license
agreement will appear. Read through the agreement then click "I do" to
agree and begin the download.
-
2
Right-click on the downloaded file and click "Extract all."
This will unzip the "Mpowerplayer" program that is needed to test Java
games on a computer.
-
3
Navigate to the Java website (see Resource 2). The Java
runtime environment is required to use the "Mpowerplayer" software.
Download the correct version of Java for the operating system installed
on your computer.
-
4
Double-click the "player.jar" file in the folder where "Mpowerplayer" was extracted. This will start the main player interface.
-
5
Download a free mobile game or demo from the Internet to
test on your computer. Sites like Mobilerated.com (see References) have
free full games as well as ad-sponsored mobile games to test out. Click
the "Download" link and click "Send to PC" to begin the file download.
-
6
Right-click on the file and click "Extract" to unzip the
contents. From within the "Mpowerplayer" click "File," then "Open," and
click on the name of the extracted game file. The extension should be
".jar." The Java game will now run on your computer.
-
1
Navigate to the Mpowerplayer website and click the
"Download now" link (see Resource 1). A pop-up window with the license
agreement will appear. Read through the agreement then click "I do" to
agree and begin the download.
Friday, June 1, 2012
What is J2ME?
J2ME stands for Java 2, Micro Edition. It is a stripped-down version
of Java targeted at devices
which have limited processing power and storage capabilities and
intermittent or fairly low-bandwidth network connections. These include
mobile phones, pagers,wireless devices
and set-top boxes among others.
A Sample Wireless Stack would consist of:
First make sure that you have the Java 2 SDK, Standard Edition (J2SE SDK), version 1.4.2 (or later). This is essential for development. If you haven't installed it, download it and install it from here http://java.sun.com/j2se/downloads/.
You absolutely MUST have the J2SE SDK installed before you install the Java Wireless Toolkit as you will be needing the tools it contains (such as javac) to compile and run your MIDlets.
Then download the J2ME Wireless Toolkit (WTK) which is available free from Sun here - http://java.sun.com/products/j2mewtoolkit/. I'm going to assume that you'll be installing this in the C:\j2mewtk\ directory, if you use another directory, just modify the paths accordingly.
Windows XP/2000: Browse to the bin folder of your project, right click on the .jar file and select Send To->Bluetooth->YOURDEVICE.
MacOS X: Click on the Bluetooth icon in the menu bar, choose Send File. Send it to your device.
This should send a message to your phone which will install the MIDlet once opened. This should work on most Nokia Series 60 phones (3650, 6600, N-Gage etc).
A Sample Wireless Stack would consist of:
- Profiles
- Configurations
- Java Virtual Machines
- Host Operating System
What is a J2ME Configuration?
A configuration defines the minimum Java technology that an application developer can expect on a broad range of implementing devices.J2ME Connected, Limited Device Configuration (CLDC)
- specifies the Java environment for mobile phone, pager and wireless devices
- CLDC devices are usually wireless
- 160 - 512k of memory available for Java
- typically has limited power or battery operated
- network connectivity, often wireless, intermittent, low-bandwidth (9600bps or less)
J2ME Connected Device Configuration (CDC)
- describes the Java environment for digital television set-top boxes, high end wireless devices and automotive telematics systems.
- device is powered by a 32-bit processor
- 2MB or more of total memory available for Java
- network connectivity, often wireless, intermittent, low-bandwidth (9600bps or less)
What is a J2ME Profile?
A specification layer above the configuration which describes the Java configuration for a specific vertical market or device type.J2ME Profiles
J2ME Mobile Information Device Profile (MIDP)
- this is the application environment for wireless devices based on the CLDC
- contains classes for user interface, storage and networking
J2ME Foundation Profile, Personal Basis, Personal and RMI profiles
- these are profiles for devices based on the CDC, which are not addressed in this tutorial
Virtual Machines
The CLDC and the CDC each require their own virtual machine because of their different memory and display capabilities. The CLDC virtual machine is far smaller than that required by the CDC and supports less features. The virtual machine for the CLDC is called the Kilo Virtual Machine (KVM) and the virtual machine for the CDC is called the CVM.Tools
PC | MacOS X | LinuxFirst make sure that you have the Java 2 SDK, Standard Edition (J2SE SDK), version 1.4.2 (or later). This is essential for development. If you haven't installed it, download it and install it from here http://java.sun.com/j2se/downloads/.
You absolutely MUST have the J2SE SDK installed before you install the Java Wireless Toolkit as you will be needing the tools it contains (such as javac) to compile and run your MIDlets.
Then download the J2ME Wireless Toolkit (WTK) which is available free from Sun here - http://java.sun.com/products/j2mewtoolkit/. I'm going to assume that you'll be installing this in the C:\j2mewtk\ directory, if you use another directory, just modify the paths accordingly.
Paths
Java needs to know where all your files are, so we need to add the location of the Java binaries to the system path.Windows 95/98
Go to Start->Run. Type in command. Then type
SET PATH=%PATH%;C:\j2mewtk\bin
You should also edit your C:\autoexec.bat file to include this line, so you
don't have to enter it every single time you restart your computer. After
you've done this, you should be able to run the tools included in the Java
Wireless Toolkit from any directory on your system. Windows 2000/XP
- Go to Control Panel -> System.
- Click on the Advanced Tab
- Click on the Environment Variables button
- Double-click the PATH variable in the System variables box
- At the end of the Variable value field, add the path to your J2ME WTK installation - for me this is something like C:\j2mewtk
- If you had to install the J2SE SDK too, it's a good idea to add the path for that - for me this is C:\j2sdk1.4.2_03 and C:\j2sdk1.4.2_03\bin. Here's what my screen looked like.
C:\> preverify
Usage: PREVERIFY.EXE [options] classnames|dirnames ...
where options include:
-classpath
Directories in which to look for classes
-d Directory in which output is written
@ Read command line arguments from a text file.
Usage: PREVERIFY.EXE [options] classnames|dirnames ...
where options include:
-classpath
Directories in which to look for classes
-d Directory in which output is written
@ Read command line arguments from a text file.
Application Development
MIDlets vs Applets
MIDlets are applets for mobile phones. Just like applets, they run in a protected sandbox - the KVM - but unlike applets, they are extremely limited. MIDP 1.0 is currently found on most Java-capable phones and is fairly restrictive. As an example - the KVM doesn't allow you to process floating point numbers yet and MIDlets written for MIDP 1.0 can't access anything outside of the sandbox without proprietary APIs from phone manufacturers. So, put your dreams of developing the ultimate MIDlet with hooks into every part of your phone OS on the backburner for a while. If you want to find out exactly how limited MIDP 1.0 is, you should probably read the spec here. Once you've done that you might want to check out MIDP 2.0 and see what Sun has fixed with that spec. For the time being we're going to write our first MIDlet - a full-featured "Hello MIDlet" application.Simple HelloMIDlet
We're going to use a program called Ktoolbar from the JAVA WTK which we installed earlier.- Go to Start->Programs->J2ME Wireless Toolkit 2.1->KToolbar.
- Click on the New Project button and name your project HelloProject and your MIDlet HelloMidlet. You should see something like this.
- Once you press Create Project, KToolbar will create a bunch of directories for your project in the apps subdirectory. We're going to ignore most of them for the moment and focus on a few important ones
- Now, fire up your favourite text editor - I like Textpad- and type in the following code
- Save this file as HelloMidlet.java in the C:\j2mewtk\apps\HelloProject\src
- Go back to KToolBar - then click on Build and then Run - you should see something like this.
- Click on the Launch softkey in the emulator to get your MIDlet to say hello. You've just written your first MIDlet!
C:\j2mewtk\apps\HelloProject - the main directory for your project
C:\j2mewtk\apps\HelloProject\bin - where Ktoolbar stores .jar, .jar and manifest.mf files
C:\j2mewtk\apps\HelloProject\classes - where the class files are stored
C:\j2mewtk\apps\HelloProject\src - where the source .java files are stored
C:\j2mewtk\apps\HelloProject\bin - where Ktoolbar stores .jar, .jar and manifest.mf files
C:\j2mewtk\apps\HelloProject\classes - where the class files are stored
C:\j2mewtk\apps\HelloProject\src - where the source .java files are stored
/* Hello Midlet - your first program*/
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class HelloMidlet
extends MIDlet
implements CommandListener {
private Form mMainForm;
public HelloMidlet() {
mMainForm = new Form("HelloMidlet");
mMainForm.append(new StringItem(null, "Hello, MIDP! \n\nYou and me - we're gonna make sweet MIDlets together! "));
mMainForm.addCommand(new Command("Exit", Command.EXIT, 0));
mMainForm.setCommandListener(this);
}
public void startApp() {
Display.getDisplay(this).setCurrent(mMainForm);
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void commandAction(Command c, Displayable s) {
notifyDestroyed();
}
}
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class HelloMidlet
extends MIDlet
implements CommandListener {
private Form mMainForm;
public HelloMidlet() {
mMainForm = new Form("HelloMidlet");
mMainForm.append(new StringItem(null, "Hello, MIDP! \n\nYou and me - we're gonna make sweet MIDlets together! "));
mMainForm.addCommand(new Command("Exit", Command.EXIT, 0));
mMainForm.setCommandListener(this);
}
public void startApp() {
Display.getDisplay(this).setCurrent(mMainForm);
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void commandAction(Command c, Displayable s) {
notifyDestroyed();
}
}
Provisioning
Okay, now how do I get my code onto my phone?
Once you've created your lovely little MIDlet and ensured that everything worked smoothly in the emulator, the next step is to get it running on an actual device. Provisioning is the name given to the process of deploying your application in such a way that it is easily downloaded and installed on the device.1. Over The Air (OTA) Provisioning
OTA provisioning allows users to download your application wirelessly using the WAP browsers built into their phones. To begin, we need to take a look at the Java Application Descriptor (JAD) file that is created when you package a MIDlet using the J2ME Wireless Toolkit. The JAD file stores information about your application and lets you modify various parameters of the MIDlet suite such as where the icon resource can be found, which MIDlets are included and where you can download the full version of the application. To edit a JAD file using the Wireless Toolkit, open your project, then click on Settings. This will open up a new window with a number of tabs - API Selection, Required, Optional, User Defined, MIDlets, Push Registry and Permissions.- API Selection This is where you choose which version of MIDP your application will use and which optional packages (JSRs) are included. The default is set to JTWI (Java Technology for the Wireless Industry) which allows you to use MIDP 2.0 as well as MMAPI and other exciting things. If you're having any problems with your application on your device try changing this to MIDP 1.0.
- Required This tab includes various options which are essential for packaging a MIDlet suite. The MIDlet-Jar-URL attribute is where we will define the location of the packaged JAR file to be downloaded to the device.
- Optional This tab includes optional parameters for your MIDlet - such as the path to the icon for the entire suite, a description and a MIDlet-Info-URL parameter.
- User Defined This tab includes user defined variables that your MIDlet can use - such as a common URL that you don't want to hard wire into the source code.
- MIDlets This tab manages all the settings for the MIDlets within your suite. At the very least you need to have one file here. This is also where you set the path to the MIDlet's icon resource.
- Push Registry This lets you configure the Push Registry which allows your MIDlet to listen and act on information received from a remote source. MIDP 2.0 Only.
- Permissions Under MIDP 1.0, applications could only access libraries packaged inside the suite - this was called the sandbox model. MIDP 2.0 introduces the concept of trusted applications which allow access beyond the sandbox. This section allows you to specify which APIs are accessible.
- Create a folder on your web server Hopefully you have an account with a web provider - login to that account and create a directory for your MIDlets to live and be served from. I created the directory http://uberthings.com/mobile/midlets. Once you've got that, you need to make a few changes to allow your server (assumed to be Apache) to serve JAD and JAR files correctly. Go to the root of your account and edit or create your .htaccess file. Add these lines:
- Specify the MIDlet-Jar-URL Click on Settings then go to the Required Tab. In the MIDlet-Jar-URL field, fill in the absolute URL of your JAR file. This will normally be something like http://mydomain/mydir/HelloProject.jar. For my server, this was http://www.uberthings.com/mobile/midlets/HelloProject.jar.
- Package your MIDlet Click on Project->Package->Create Package. This will create a .jar and a .jad file in your applications bin folder. For my application - this was c:\j2mewtk\apps\HelloProject\bin\HelloProject.jar and c:\j2mewtk\apps\HelloProject\bin\HelloProject.jad.
- Upload the packaged MIDlet suite Upload the JAR and JAD files that the packaging operation created to the folder you created earlier.
- Test with your device Open the WAP browser on your phone and point it to the URL of the JAD file. Using my example, this would be http://uberthings.com/mobile/midlets/HelloProject.jad. Your device should then prompt you to download and install the MIDlet. Carry it around and show it off to all your friends!
AddType text/vnd.sun.j2me.app-descriptor jad
AddType application/java-archive jar
Save this file. If you're not using Apache, ensure that your MIME types include the above two settings.
2. Cable / Bluetooth
If you've got a Bluetooth adaptor or a USB cable which connects directly to your phone, you can use this to quickly test your packaged midlet.Windows XP/2000: Browse to the bin folder of your project, right click on the .jar file and select Send To->Bluetooth->YOURDEVICE.
MacOS X: Click on the Bluetooth icon in the menu bar, choose Send File. Send it to your device.
This should send a message to your phone which will install the MIDlet once opened. This should work on most Nokia Series 60 phones (3650, 6600, N-Gage etc).
Link: http://uberthings.com/mobile/
Subscribe to:
Posts (Atom)