GPS SPOT Updated

So it's been a while since I've posted anything of value. And even longer since I posted of the GPS SPOT. But given that we have just released yesterday the latest v4.0 (Blue) SDK, and I released v4.0 of the Sun SPOT Manager Tool, as well as a new set of Getting Started Docs, I figure it#8217s time to post something else here.


So we#8217ve been working on a project with some folks at Vodafone with Sun SPOTs, and they have been hard at work hooking up the Precon Temperature and Humidity Sensor as outlined in my previous blog post. But it#8217s also been almost 2 years since I first blogged about the GPS SPOT, and so much has changed since then. So, here goes #8230


To start with, I have completely reworked the NMEA Message Parser to be a bit better. This is a small utility class that parses an NMEA Message and puts it in a Hashtable which can be easily dereferenced later for the individual elements that are of interest.



package org.sunspotworld;
import java.util.Hashtable;
/\*\*
\*
\* @author davidgs
\*/

public class parser {
private String[] Fields;
public parser(String[] fields){
Fields = fields;


}




public Hashtable parseMessage(String m){
Hashtable thisHash = new Hashtable();
String msg = m;
int nToke =0;
int del = m.indexOf(',');
msg = msg.substring(del+1); // scrub the header
del = msg.indexOf(',');
for(int x = 0; x< Fields.length;x++){
String val = msg.substring(0,del);
thisHash.put(Fields[x], val);
if(del+1 <= msg.length())
msg = msg.substring(del+1);
del = msg.indexOf(',');
if(del < 0){
if(msg.indexOf('\*')>0){
del = msg.indexOf('\*');
}else {
del = msg.length();
}
}
}
return thisHash;
}
}



So I will use that parser class in each of the NMEA Message classes. I made a separate class for each type of message I#8217m interested in, but the only really important bits in any of them are the fields, defined as an array of Strings.

package org.sunspotworld;
import java.util.Hashtable;
public class GPRMCMessage {

static final String[] GPRMCfields = {"UTCTime","Status","Latitude","North-South","Longitude","East-West","Speed","Course","Date","MagneticVariation","Checksum"};
private parser parse = new parser(GPRMCfields);
private Hashtable parsedMessage = new Hashtable();
public GPRMCMessage(String message){
parsedMessage = parse.parseMessage(message);
}
public String getUTCTime() {
return getValue("UTCTime");
}
public String getLatitude() {
return getValue("Latitude");
}
public String getLongitude() {
return getValue("Longitude");
}
public String getSpeed() {
return getValue("Speed");
}
public String getCourse() {
return getValue("Course");
}
public String getDate() {
return getValue("Date");
}
public String getMagneticVariation() {
return getValue("MagneticVariation");
}
public String getChecksum() {
return getValue("Checksum");
}
public String getValue(String key){
return (String) parsedMessage.get(key);
}
}


I defined some convenience methods to return fields I know I#8217m going to want, but there is also a general getValue(String) method so that I can get access to any field in the message. So a typical GPGGA might contain: $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,\*47 And I can then create a new GPGGAMessage Object with that String:

package org.sunspotworld;
import java.util.Hashtable;

public class GPGGAMessage {

static final String[] GPGGAfields = {"UTCTime","Latitude","North-South","Longitude","East-West","Position-Fix","Satellites-Used","HDOP","Altitude","Alt-Units","GEOID","GEOID-Units",
"Age-of-Diff","Diff-Station-ID","Checksum"};
private Hashtable parsedMessage;
private parser parse = new parser(GPGGAfields);

public GPGGAMessage(String message){
parsedMessage = parse.parseMessage(message);
}



public String getUTCTime() {
return getValue("UTCTime");
}
public String getLatitude() {
return getValue("Latitude");
}
public String getLongitude() {
return getValue("Longitude");
}
public String getSatellitesUsed() {
return getValue("Satellites-Used");
}
public String getHDOP() {
return getValue("HDOP");
}
public String getAltitude() {
return getValue("Altitude");
}
public String getGeoid() {
return getValue("GEOID");
}
public String getChecksum() {
return getValue("Checksum");
}
public String getValue(String key){
return (String) parsedMessage.get(key);
}
}

And now I can reference fields in that message quickly and easily. But how do you get those messages? Well, that#8217s actually the easy part. So let#8217s look at that part.


First, you need a GPS Unit. I used the San Jose Technology, Inc. FV-M8 GPS Unit, since that#8217s what I had. And here#8217s the wiring diagram for it:





wiring.png




So pin 1 went to the 5v pin on the Sun SPOT header, pin 2 went to ground, pin 3 to D0, and pin 4 to D1 (Tx and Rx, respectively). That was all it took. And then the following code to read the values:





/\*
\* StartApplication.java
\*
\* Created on May 2, 2008 1:35:38 AM;
\*/

package org.sunspotworld;
import com.sun.spot.peripheral.Spot;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.peripheral.ISwitch;
import com.sun.spot.sensorboard.peripheral.ITriColorLED;
import com.sun.spot.peripheral.radio.IRadioPolicyManager;
import com.sun.spot.io.j2me.radiostream.\*;
import com.sun.spot.io.j2me.radiogram.\*;
import com.sun.spot.util.\*;
import com.sun.squawk.Isolate;
import java.io.\*;
import javax.microedition.io.\*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
/\*\*
\* The startApp method of this class is called by the VM to start the
\* application.
\*
\* The manifest specifies this class as MIDlet-1, which means it will
\* be selected for execution.
\*/

public class StartApplication extends MIDlet {

private ITriColorLED [] leds = EDemoBoard.getInstance().getLEDs();

protected void startApp() throws MIDletStateChangeException {
System.out.println("Hello, world");
new BootloaderListener().start(); // monitor the USB (if connected) and recognize commands from host

long ourAddr = Spot.getInstance().getRadioPolicyManager().getIEEEAddress();
System.out.println("Our radio address = " + IEEEAddress.toDottedHex(ourAddr));
enableGPS();
}

protected void pauseApp() {
// This is not currently called by the Squawk VM
}

/\*\*
\* Called if the MIDlet is terminated by the system.
\* I.e. if startApp throws any exception other than MIDletStateChangeException,
\* if the isolate running the MIDlet is killed with Isolate.exit(), or
\* if VM.stopVM() is called.
\*
\* It is not called if MIDlet.notifyDestroyed() was called.
\*
\* @param unconditional If true when this method is called, the MIDlet must
\* cleanup and release all resources. If false the MIDlet may throw
\* MIDletStateChangeException to indicate it does not want to be destroyed
\* at this time.
\*/

protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {
for (int i = 0; i < 8; i++) {
leds[i].setOff();
}
}
GPS telitGSM;
/\*\*
\* calling this method will break the USB serial i/o ( System.out and System.err )
\*/

public void enableGPS() {
System.out.println("getting edemoserial");
// setup the GPS on arm9 serial port
try {
StreamConnection strm = (StreamConnection) Connector.open("edemoserial://usart?baudrate=38400");
// full options string : serial://usart?baudrate=9600&databits=8&stopbits=1&parity=none
telitGSM = new GPS(strm);
} catch (Exception e) {
// unable to initialize the telit ... we need an error logging system
e.printStackTrace();
}

}
}


So that opens the serial connection to the GPS Unit, and then:




/\*
\* To change this template, choose Tools | Templates
\* and open the template in the editor.
\*/

package org.sunspotworld;
import com.sun.spot.util.Queue;
import com.sun.spot.util.Utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.StreamConnection;
/\*\*
\*/

public class GPS {

public StreamConnection serialStream = null;
public OutputStream serialOutput = null;
public InputStreamer monitor = null;
/\*\*
\* this is to sync writing and reading
\*/

private Queue input;
private Position position;
private Position temp;
private boolean isValid = false;
private NMEA nmea;

public GPS(StreamConnection serial) {
serialStream = serial;
nmea = new NMEA();
init();
}

protected void init() {

try {
serialOutput = serialStream.openOutputStream();
monitor = new InputStreamer(serialStream.openInputStream());
new Thread(monitor).start();
} catch (Exception e) {
}
}

public void setIsValid(boolean isValid) {
this.isValid = isValid;
}

public class InputStreamer implements Runnable {

InputStream stream;

public InputStreamer(InputStream strm) {
stream = strm;
}

/\*
\* reads input builds a sentance then tries to parse it
\*
\*/

public void run() {

System.out.println("GPS: running........");
char val;
String sentence = "";

while (true) {
try {
val = (char) stream.read();
if (val == '\\n') {
if (sentence.charAt(0) == '$') {
if (sentence.startsWith("$GPGGA")) {
//System.out.println("GPGGA NEMA Message: " + message);
GPGGAMessage gpgga = new GPGGAMessage(sentence);
System.out.println("Latitude: " + gpgga.getLatitude());
System.out.println("Longitude: " + gpgga.getLongitude());
} else if (sentence.startsWith("$GPGSA")) {
GPGSAMessage gpgsa = new GPGSAMessage(sentence);
// do what you want here
} else if (sentence.startsWith("$GPRMC")) {
GPRMCMessage gprmc = new GPRMCMessage(sentence);
// do what you want here
} else {
System.out.println("Other NEMA Message: " + sentence);
// or create new Message classes to handle them
}
sentence = "";
} else {
sentence = "";
}
} else {
// recover from bad read .. reset
if (val == '$') {
sentence = "";
}
sentence += (char) val;
}
// Utils.sleep(10000);
} catch (IOException ex) {
Utils.sleep(100);
} catch (Exception e) {
}
}
}
}
}



And there you have it. Simple. Easy. And you get GPS from a Sun SPOT.


[ A bird in the hand makes it awfully hard to blow your nose. ]

Comments:

wowwwwwwww
this is very good post , thank you for posting this and sharing with us .

Posted by Michal fefer on November 25, 2008 at 07:21 PM EST #

Post a Comment:
Comments are closed for this entry.
About

user9157252

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today