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
No comments:
Post a Comment