Working with Bluetooth and GPS: Part 2 - Parsing GPS Data and Rendering a Map
This article is the second of a two-part series on how to use Java ME technology and Bluetooth to access location data from wireless GPS devices.
Contents
- | Parsing the NMEA Sentences |
- | Requesting a Map Image from an External Map Service |
- | Parsing the XML Result from the Map Service |
- | Conclusion |
As you may recall from Part 1 of this series, it is very easy to access the raw GPS data from a Bluetooth-enabled GPS device. The listing below shows what the serial output from a typical GPS device would look like:
Listing 1. NMEA Formatted GPS Data
$GPGSV,3,3,10,31,76,012,31,32,60,307,38,,,,,,,,*72 $GPGSA,A,3,32,31,16,11,23,,,,,,,,4.5,3.1,3.3*34 $GPRMC,122314.000,A,3659.249,N,09434.910,W,0.0,0.0,220908,0.0,E*78 $GPGGA,122314.000,3659.24902,N,09434.91042,W,1,05,3.1,261.51,M,-29.1,M,,*58 $GPGSV,3,1,10,01,62,343,00,11,14,260,34,14,35,079,27,16,29,167,28*73 $GPGSV,3,2,10,20,44,309,00,22,13,145,00,23,08,290,31,30,23,049,33*7C $GPGSV,3,3,10,31,76,012,31,32,60,307,38,,,,,,,,*72 $PSTMECH,32,7,31,7,00,0,00,0,14,4,30,4,16,7,00,0,11,7,23,7,00,0,00,0*50 $GPRMC,122315.000,A,3659.249,N,09434.910,W,0.0,0.0,220908,0.0,E*79 $GPGGA,122315.000,3659.24902,N,09434.91048,W,1,05,3.1,261.61,M,-29.1,M,,*50 |
As you also may recall from Part 1, a GPS device encodes its data according to the NMEA specification. The purpose of this article is to learn how to accomplish the following tasks:
- Parse the NMEA sentence data from a GPS device to retrieve the latitude and longitude values
- Request a map image of our current location from a external map service
- Parse the XML result data from the map service and render the map image on the mobile device
Parsing the NMEA Sentences
$GPGGA,123519,4807.038,N,01131.324,E,1,08,0.9,545.4,M,46.9,M, ,; |
After further inspection, you can now see that the individual parts of an NMEA sentence are separated by commas. The following facts can be obtained from the preceding NMEA sentence:
- the GPS fix was taken at 12:35:19 UTC time
- the latitude coordinate is 48 degrees and 07.038 minutes North
- the longitude coordinate is 11 degrees and 31.234 minutes East
- the GPS fix quality is 1
- 8 GPS satellites were being tracked
- the horizontal dilution of position was 0.9
- the altitude of the GPS fix was 545.4 meters
- the height of the geoid was 46.9 meters
StringTokenizer
class, right? Unfortunately, it's not that easy since the StringTokenizer
class only exists in Java SE implementations. However, in the example
code I've included a simple NMEA parser and String tokenization classes.
The following is a code snippet from Parser.java
that properly converts coordinate DMS format (degrees, minutes, seconds) to decimal degree values.
Listing 2. Code Snippet from
Parser.java
if (token.endsWith("$GPGGA")) { type = TYPE_GPGGA; // Time of fix tokenizer.next(); // Latitude String raw_lat = tokenizer.next(); String lat_deg = raw_lat.substring(0, 2); String lat_min1 = raw_lat.substring(2, 4); String lat_min2 = raw_lat.substring(5); String lat_min3 = "0." + lat_min1 + lat_min2; float lat_dec = Float.parseFloat(lat_min3)/.6f; float lat_val = Float.parseFloat(lat_deg) + lat_dec; // Latitude direction String lat_direction = tokenizer.next(); if(lat_direction.equals("N")){ // do nothing } else { lat_val = lat_val * -1; } record.latitude = lat_val + ""; // Longitude String raw_lon = tokenizer.next(); String lon_deg = raw_lon.substring(0, 3); String lon_min1 = raw_lon.substring(3, 5); String lon_min2 = raw_lon.substring(6); String lon_min3 = "0." + lon_min1 + lon_min2; float lon_dec = Float.parseFloat(lon_min3)/.6f; float lon_val = Float.parseFloat(lon_deg) + lon_dec; // Longitude direction String lon_direction = tokenizer.next(); if(lon_direction.equals("E")){ // do nothing } else { lon_val = lon_val * -1; } record.longitude = lon_val + ""; record.quality = tokenizer.next(); record.satelliteCount = tokenizer.next(); record.dataFound = true; // Ignore rest return 200; } |
Now that we've properly parsed the NMEA sentence, let's explore how to get a map using an external mapping service.
Requesting a Map Image from an External Map Service
- All the options can be specified in URL parameters in a single HTTP request.
- No external libraries are needed to consume the API.
- The response comes back as simple XML document that can be easily parsed.
- The resulting map image is in PNG format, which all MIDP devices support.
- latitude: 46.987484
- longitude: -84.58184
- image width: 400 pixels
- image height: 400 pixels
- zoom level: 7
http://local.yahooapis.com/MapsService/V1/mapImage?appid= YOUR_YAHOO_ID_KEY&latitude=46.987484&longitude=- 84.58184&image_width=400&image_height=400&zoom=7 |
Pretty simple, huh? The result of this request is not the image itself, but an XML document that has a link to the image. The listing below shows the XML result of my HTTP request for a map image:
Listing 3. XML Result from the Yahoo! Maps Service
<?xml version="1.0"?> <Result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> http://gws.maps.yahoo.com/mapimage?MAPDATA=Voo4MOd6wXXT6pG.WpNC6XPETWAN8WDUsxa 8qRQ2kzC_f8vO7.FvQhW3hSbWbF_jO3H4.J2Gb7Qhc2vqoCTL0DWbaCfT751_Zt9Ysqtg0dKo2mv95 EIc4bbgdYrmebNqFcwfKb8YhOFe38Ia3Q--&mvt=m?cltype=onnetwork&.intl=us </Result>
Parsing the XML Result from the Map Service
You should also be glad to know that the JSR-172 API has been out for several years and is available on a wide variety of mobile handsets. Of course, the JSR-172 API is a part of the Java ME MSA standard, so if your handset supports MSA then you're obviously good to go.
In the following listing, you can see that my XML parsing class only needed to extend the
DefaultHandler
class in the JSR-172 API. Since we're only interested in the contents of a single tag, namely the <Result>
tag, then the code necessary to retrieve the URL for the map image is fairly simple.
Listing 4. A Simple XML Parsing Class Using the JSR-172 API
public class SimpleHandler extends DefaultHandler { public String image_url = null; public SimpleHandler() {} public void startDocument() throws SAXException {} public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if(qName.equals("Result")) { // do nothing } else { throw new SAXException("<Result> tag not found"); } } public void characters(char[] ch, int start, int length) throws SAXException { image_url = new String(ch, start, length).trim(); } public void endElement(String uri, String localName, String qName, Attributes attributes) throws SAXException{} public void endDocument() throws SAXException{} public String getImageURL(){ return image_url; } } |
Now the code in Listing 4, specifically the
getImageURL()
method, will return the URL that points to the PNG image of the map of
our current location. The only remaining step is to make another HTTP
request to retrieve the image and display it on the mobile device.Conclusion
Hopefully, the example code presented in this article will inspire you to create some really exciting location-based applications!
Link :
No comments:
Post a Comment