Show NmeaService.java syntax highlighted
/*
* Copyright (c) 2005
* Helsinki Institute of Physics
* see LICENSE file for details
*
* Nmea.java
* Created on Dec 15, 2004
*/
package fi.hip.gb.bluetooth;
import java.io.DataInputStream;
import java.io.EOFException;
import java.util.Calendar;
import javax.bluetooth.ServiceRecord;
import fi.hip.gb.bluetooth.coordconv.LatitudeLongitude;
import fi.hip.gb.bluetooth.util.Properties;
import fi.hip.gb.bluetooth.util.StringTokenizer;
import fi.hip.gb.midlet.util.Float;
/**
* Socket handler for reading NMEA messages from bluetooth GPS. Runs in a
* new thread until {@link fi.hip.gb.bluetooth.Service#closeConnection()}
* method is called. Received sentences are sent to
* {@link fi.hip.gb.bluetooth.BTListener#handleAction(String, EndPoint, Object)}
* implementation. Storage contains a result with GPS data in the property field.
* <p>
* Currently supports following NMEA sentences:
* $GPRMC<br>
* $GPGGA
*
* @author Juho Karppinen
*/
public class NmeaService extends Service {
public final static String SENTENCE = "sentence";
public final static String DATETIME = "date";
//public final static String LATITUDE = "latitude";
public final static String LATITUDE_DEG = "latitude_deg";
public final static String LATITUDE_MIN = "latitude_min";
public final static String LATITUDE_SEC = "latitude_sec";
public final static String LATITUDE_NS = "latitude_ns";
//public final static String LONGITUDE = "longitude";
public final static String LONGITUDE_DEG = "longitude_deg";
public final static String LONGITUDE_MIN = "longitude_min";
public final static String LONGITUDE_SEC = "longitude_sec";
public final static String LONGITUDE_EW = "longitude_ew";
public final static String FIX = "fix";
public final static String SATELLITES = "satellites";
public final static String HORIZONTAL_ACC = "horizontal_accuracy";
public final static String ALTITUDE = "altitude";
public final static String SPEED = "speed";
public final static String HEADING = "heading";
/**
* Constructs a NMEA reader
* @param endpt the endpoint where data is downloaded
* @param url connection string to the bluetooth GPS
*/
public NmeaService(EndPoint endpt, String url) {
super(endpt, url);
this.reader = new Reader();
}
/**
* Constructs a NMEA reader
* @param endpt the endpoint where data is downloaded
* @param svcRec record of the service
*/
public NmeaService(EndPoint endpt, ServiceRecord svcRec) {
super(endpt, svcRec);
this.reader = new Reader();
}
private void parse(String sentence) {
BTService.getInstance().log("parsing " + new String(sentence));
StringTokenizer st = new StringTokenizer(sentence, ",");
if(!st.hasMoreTokens())
return;
String op = st.nextToken();
Properties prop = new Properties();
prop.setProperty(SENTENCE, op);
if(op.equals("$GPGGA")) {
// $GPGGA,104856.324,4614.1920,N,00602.3681,E,1,04,4.6,542.2,M,48.2,M,0.0,0000*75
// $GPGGA,170834,4124.8963,N,08151.6838,W,1,05,1.5,280.2,M,-34.0,M,,,*75
// Global Positioning System Fix Data
// Sentence Identifier $GPGGA Global Positioning System Fix Data
// Time 170834 17:08:34 UTC
// Latitude 4124.8963, N 41d 24.8963' N or 41d 24' 54" N
// Longitude 08151.6838, W 81d 51.6838' W or 81d 51' 41" W
// Fix Quality:
// - 0 = Invalid
// - 1 = GPS fix
// - 2 = DGPS fix 1 Data is from a GPS fix
// Number of Satellites 05 5 Satellites are in view
// Horizontal Dilution of Precision (HDOP) 1.5 Relative accuracy of horizontal position
// Altitude 280.2, M 280.2 meters above mean sea level
// Height of geoid above WGS84 ellipsoid -34.0, M -34.0 meters
// Time since last DGPS update blank No last update
// DGPS reference station id blank No station id
// Checksum *75 Used by program to check for transmission errors
String time = st.nextToken();
LatitudeLongitude ll = getLatLon(st.nextToken(), st.nextToken(), st.nextToken(), st.nextToken());
//prop.setProperty(LATITUDE, ll.getLatitude().toString());
//prop.setProperty(LATITUDE_NS, ll.getLatitudeNS());
//prop.setProperty(LONGITUDE, ll.getLongitude().toString());
//prop.setProperty(LONGITUDE_EW, ll.getLongitudeEW());
prop.setProperty(FIX, st.nextToken());
prop.setProperty(SATELLITES, st.nextToken());
prop.setProperty(HORIZONTAL_ACC, st.nextToken());
prop.setProperty(ALTITUDE, st.nextToken());
this.sendData(prop);
} else if(op.equals("$GPRMC")) {
// eg1. $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62
// eg2. $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
// Recommended Minimum Specific GPS/TRANSIT Data
// 225446 Time of fix 22:54:46 UTC
// A Navigation receiver warning A = Valid position, V = Warning
// 4916.45,N Latitude 49 deg. 16.45 min. North
// 12311.12,W Longitude 123 deg. 11.12 min. West
// 000.5 Speed over ground, Knots
// 054.7 Course Made Good, degrees true
// 191194 UTC Date of fix, 19 November 1994
// 020.3,E Magnetic variation, 20.3 deg. East
// *68 mandatory checksum
BTService.getInstance().log("start");
String time = st.nextToken();
BTService.getInstance().log("time");
String validity = st.nextToken();
BTService.getInstance().log("valid");
int status = 0;
if(validity.toUpperCase().equals("A"))
status = 1;
prop.setProperty(FIX, Integer.toString(status));
BTService.getInstance().log("latlong");
LatitudeLongitude ll = getLatLon(st.nextToken(), st.nextToken(), st.nextToken(), st.nextToken());
String[] arr = ll.getLatitude();
BTService.getInstance().log("lat " + arr.length);
prop.setProperty(LATITUDE_DEG, arr[0]);
prop.setProperty(LATITUDE_MIN, arr[1]);
prop.setProperty(LATITUDE_SEC, arr[2]);
prop.setProperty(LATITUDE_NS, ll.getLatitudeNS());
arr = ll.getLongitude();
BTService.getInstance().log("lng " + arr.length);
prop.setProperty(LONGITUDE_DEG, arr[0]);
prop.setProperty(LONGITUDE_MIN, arr[1]);
prop.setProperty(LONGITUDE_SEC, arr[2]);
prop.setProperty(LONGITUDE_EW, ll.getLongitudeEW());
BTService.getInstance().log("speed");
Float kmh = new Float(Float.parse(st.nextToken()).Div(Float.parse("0.01852")).toLong()).Div(100);
prop.setProperty(SPEED, kmh.toString());
//int kmh = (int)(Float.parseFloat(st.nextToken()) / Float.parseFloat("0.01852"));
//prop.setProperty(SPEED, Float.toString(((float)kmh) / 100));
BTService.getInstance().log("heading");
prop.setProperty(HEADING, st.nextToken());
BTService.getInstance().log("date");
String date = st.nextToken();
long datetime = getDateTime(date, time);
prop.setProperty(DATETIME, Long.toString(datetime));
BTService.getInstance().log("send");
this.sendData(prop);
}
}
private void sendData(Properties prop) {
// pass the message to the GUI
GPSResult res = new GPSResult();
res.setName("GPS data from " + this.endpt.getName());
res.setType(GPSResult.GPS_TYPE);
res.setFlags(prop);
BTService.getInstance().fireEvent(BTListener.EVENT_RECEIVED,
this.endpt,
res);
}
/**
* Gets the date and time from satellite.
* @return
*/
public long getDateTime(String date, String time) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(date.substring(0,2)));
cal.set(Calendar.MONTH, Integer.parseInt(date.substring(2,4)));
cal.set(Calendar.YEAR, Integer.parseInt(date.substring(4,6)));
cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(time.substring(0,2)));
cal.set(Calendar.MINUTE, Integer.parseInt(time.substring(2,4)));
cal.set(Calendar.SECOND, Integer.parseInt(time.substring(4,6)));
//return cal.getTimeInMillis();
return cal.getTime().getTime();
}
/**
* Gets the latitude and longitude in normal decimal system
* @param lat latitude in format 1234.5678, means 12deg 34min 0.5678sec
* @param lat_ns S for south, and N for north
* @param lng longitude in format 1234.5678, means 12deg 34min 0.5678sec
* @param lng_ew W for west, and E for east
* @return
*/
private LatitudeLongitude getLatLon(String lat, String lat_ns, String lng, String lng_ew) {
try {
int degreesN = Integer.parseInt(lat.substring(0, 2));
if(lat_ns.toUpperCase().equals("S"))
degreesN *= -1;
int minutesN = Integer.parseInt(lat.substring(2, 4));
Float secondsN = Float.parse("0." + lat.substring(5)).Mul(60);
//Float secondsN = new Float(Float.parseFloat("0." + lat.substring(5)) * 60);
//double secondsN = 60.d * Double.parseDouble("0." + lat.substring(5));
int degreesE = Integer.parseInt(lng.substring(0, 3));
if(lng_ew.toUpperCase().equals("W"))
degreesE *= -1;
int minutesE = Integer.parseInt(lng.substring(3, 5));
Float secondsE = Float.parse("0." + lat.substring(6)).Mul(60);
//Float secondsE = new Float( Float.parseFloat("0." + lng.substring(6)) * 60);
//return new LatitudeLongitude(degreesN, degreesE);
return new LatitudeLongitude(degreesN, minutesN, secondsN,
degreesE, minutesE, secondsE);
} catch(Exception e) {
System.out.println(lat + " " + lng);
e.printStackTrace();
return null;
}
}
/**
* Gets the status of GPS.
* @return
*
public String getStatus() {
if(this.status == 1) {
return "fix";
} else if(this.status == 2) {
return "DGPS fix";
} else {
return "Invalid";
}
}*/
class Reader implements Runnable {
public void run() {
try {
BTService.getInstance().log("opening input from GPS");
DataInputStream datain =
NmeaService.this.getConnection().openDataInputStream();
int i = 0;
// maximum length of NMEA sentence is 82 characters
byte[] sentence = new byte[182];
while(! NmeaService.this.done) {
byte c = datain.readByte();
if(c == '$' || i >= sentence.length) {
i = 0;
}
sentence[i] = c;
if(c == '\n' && sentence[0] == '$') {
parse(new String(sentence, 0, i));
}
i++;
}
datain.close();
} catch(EOFException eofe) {
BTService.getInstance().log("stream closed from " + endpt);
} catch (Exception e) {
BTService.getInstance().log("failed to read from " + endpt
+ ": " + e.getClass().toString() + " " + e.getMessage());
e.printStackTrace();
//MIDui.showException("cannot read over bluetooth from " + endPoint.remoteName, e, null);
}
// remove the endpoint
BTService.getInstance().fireEvent(BTListener.EVENT_LEAVE,
NmeaService.this.endpt,
null);
//endPoint.btnet.cleanupRemoteEndPoint(endPoint);
BTService.getInstance().log("Reader thread exit for " + endpt.getName());
}
}
}
See more files for this project here