package project.latex.balloon.sensor.gps;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author will
*/
import project.latex.balloon.sensor.SensorReadFailedException;
import java.util.HashMap;
import org.apache.log4j.Logger;
public class PolledSentenceParser {
private static final Logger logger = Logger.getLogger(PolledSentenceParser.class);
private PolledSentenceParser() {
}
public static HashMap<String, String> parse(String polledSentence) throws SensorReadFailedException {
HashMap<String, String> polledData = new HashMap<>();
String[] polledTokens = polledSentence.split(",", -1);
if (polledTokens[0].equals("$PUBX") && polledTokens.length == 21) {
// Do the checksum for the given data.
try {
String expectedChecksum = calculateChecksum(polledSentence);
String receivedChecksum = polledTokens[20].substring(2, 4);
if (!receivedChecksum.equals(expectedChecksum)) {
throw new SensorReadFailedException("Invalid checksum for GPS data.");
}
} catch (StringIndexOutOfBoundsException ex) {
throw new SensorReadFailedException("Invalid checksum format, "
+ "cannot do checksum" + ex);
}
polledData = parseTokens(polledTokens);
} else {
throw new SensorReadFailedException("Invalid polled sentence,"
+ " cannot parse.");
}
return polledData;
}
private static String calculateChecksum(String data) {
int checksum = 0;
if (data.startsWith("$")) {
data = data.substring(1, data.length());
}
int end = data.indexOf('*');
if (end == -1) {
end = data.length();
}
for (int i = 0; i < end; i++) {
checksum = checksum ^ data.charAt(i);
}
String hex = Integer.toHexString(checksum);
if (hex.length() == 1) {
hex = "0" + hex;
}
return (hex.toUpperCase());
}
private static HashMap<String, String> parseTokens(String[] polledTokens) throws SensorReadFailedException {
HashMap<String, String> parsedData = new HashMap<>();
// Check that we hava a GPS fix.
if (polledTokens[8].equals("NF")) {
logger.info("No GPS Fix");
return parsedData;
}
// Get time as "HH:MM:SS".
String time = polledTokens[2];
try {
time = time.substring(0, 2) + ":"
+ time.substring(2, 4) + ":"
+ time.substring(4, 6);
} catch (StringIndexOutOfBoundsException ex) {
throw new SensorReadFailedException("GPS time data unavailable"
+ "or corrupted:" + ex);
}
// Get latitude and longitude in decimal form.
String latitude = latitudeToDecimal(polledTokens[3], polledTokens[4]);
String longitude = longitudeToDecimal(polledTokens[5], polledTokens[6]);
// Get altitude in meters.
String altitude = polledTokens[7];
// Get speed in kph.
String speed = polledTokens[11];
// Get heading as a clockwise angle relative to North.
String heading = polledTokens[12];
parsedData.put("time", time);
parsedData.put("latitude", latitude);
parsedData.put("longitude", longitude);
parsedData.put("altitude", altitude);
parsedData.put("speed", speed);
parsedData.put("heading", heading);
return parsedData;
}
private static String latitudeToDecimal(String latitude, String heading) {
double degrees = Double.parseDouble(latitude.substring(0, 2));
double minutes = Double.parseDouble(latitude.substring(2));
double decimalLatitude = degrees + (minutes / 60);
if (heading.equals("S")) {
decimalLatitude *= -1;
}
return String.valueOf(decimalLatitude);
}
private static String longitudeToDecimal(String longitude, String heading) {
double degrees = Double.parseDouble(longitude.substring(0, 3));
double minutes = Double.parseDouble(longitude.substring(3));
double decimalLongitude = degrees + (minutes / 60);
if (heading.equals("W")) {
decimalLongitude *= -1;
}
return String.valueOf(decimalLongitude);
}
}