Last active
August 30, 2023 07:07
-
-
Save javisantana/1326141 to your computer and use it in GitHub Desktop.
NMEA parser in java which does not suck
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
this software is under the terms of MIT license: http://opensource.org/licenses/MIT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package es.agroguia.model; | |
import java.util.HashMap; | |
import java.util.Map; | |
public class NMEA { | |
interface SentenceParser { | |
public boolean parse(String [] tokens, GPSPosition position); | |
} | |
// utils | |
static float Latitude2Decimal(String lat, String NS) { | |
float med = Float.parseFloat(lat.substring(2))/60.0f; | |
med += Float.parseFloat(lat.substring(0, 2)); | |
if(NS.startsWith("S")) { | |
med = -med; | |
} | |
return med; | |
} | |
static float Longitude2Decimal(String lon, String WE) { | |
float med = Float.parseFloat(lon.substring(3))/60.0f; | |
med += Float.parseFloat(lon.substring(0, 3)); | |
if(WE.startsWith("W")) { | |
med = -med; | |
} | |
return med; | |
} | |
// parsers | |
class GPGGA implements SentenceParser { | |
public boolean parse(String [] tokens, GPSPosition position) { | |
position.time = Float.parseFloat(tokens[1]); | |
position.lat = Latitude2Decimal(tokens[2], tokens[3]); | |
position.lon = Longitude2Decimal(tokens[4], tokens[5]); | |
position.quality = Integer.parseInt(tokens[6]); | |
position.altitude = Float.parseFloat(tokens[9]); | |
return true; | |
} | |
} | |
class GPGGL implements SentenceParser { | |
public boolean parse(String [] tokens, GPSPosition position) { | |
position.lat = Latitude2Decimal(tokens[1], tokens[2]); | |
position.lon = Longitude2Decimal(tokens[3], tokens[4]); | |
position.time = Float.parseFloat(tokens[5]); | |
return true; | |
} | |
} | |
class GPRMC implements SentenceParser { | |
public boolean parse(String [] tokens, GPSPosition position) { | |
position.time = Float.parseFloat(tokens[1]); | |
position.lat = Latitude2Decimal(tokens[3], tokens[4]); | |
position.lon = Longitude2Decimal(tokens[5], tokens[6]); | |
position.velocity = Float.parseFloat(tokens[7]); | |
position.dir = Float.parseFloat(tokens[8]); | |
return true; | |
} | |
} | |
class GPVTG implements SentenceParser { | |
public boolean parse(String [] tokens, GPSPosition position) { | |
position.dir = Float.parseFloat(tokens[3]); | |
return true; | |
} | |
} | |
class GPRMZ implements SentenceParser { | |
public boolean parse(String [] tokens, GPSPosition position) { | |
position.altitude = Float.parseFloat(tokens[1]); | |
return true; | |
} | |
} | |
public class GPSPosition { | |
public float time = 0.0f; | |
public float lat = 0.0f; | |
public float lon = 0.0f; | |
public boolean fixed = false; | |
public int quality = 0; | |
public float dir = 0.0f; | |
public float altitude = 0.0f; | |
public float velocity = 0.0f; | |
public void updatefix() { | |
fixed = quality > 0; | |
} | |
public String toString() { | |
return String.format("POSITION: lat: %f, lon: %f, time: %f, Q: %d, dir: %f, alt: %f, vel: %f", lat, lon, time, quality, dir, altitude, velocity); | |
} | |
} | |
GPSPosition position = new GPSPosition(); | |
private static final Map<String, SentenceParser> sentenceParsers = new HashMap<String, SentenceParser>(); | |
public NMEA() { | |
sentenceParsers.put("GPGGA", new GPGGA()); | |
sentenceParsers.put("GPGGL", new GPGGL()); | |
sentenceParsers.put("GPRMC", new GPRMC()); | |
sentenceParsers.put("GPRMZ", new GPRMZ()); | |
//only really good GPS devices have this sentence but ... | |
sentenceParsers.put("GPVTG", new GPVTG()); | |
} | |
public GPSPosition parse(String line) { | |
if(line.startsWith("$")) { | |
String nmea = line.substring(1); | |
String[] tokens = nmea.split(","); | |
String type = tokens[0]; | |
//TODO check crc | |
if(sentenceParsers.containsKey(type)) { | |
sentenceParsers.get(type).parse(tokens, position); | |
} | |
position.updatefix(); | |
} | |
return position; | |
} | |
} |
- No "try.. catch" in parseFloats - the NMEA receivers in non-established state cause exception and overall fault
- No "GNGGA" and others - mainly now data is gathered from GPS, GLONASS and Galileo +BeiDou sometimes and reports GNRMC etc not GPRMC and etc.
- No support for feeding data(incomplete sentences will be lost)
- does not suck 👍
Not too much good...Lat and Lon must to be double instead of float
thanks for the comments. This code is not meant to do everything but is that simple that you can modify and adapt to your needs. So instead of using a huge library you don't understand, you use a small piece of code you know how it works and everybody can read and understand in 5 minutes.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
pls. any help as I am also a new java user
why no result shown when running this example
public class TestMain
{
static String GPGGA_Test = "$GPGGA,211034,4738.9577,N,12220.9329,W,1,09,1.0,10.8,M,-18.4,M,,*42";
public static void main(String [ ] args)
{
NMEA nmea = new NMEA();
nmea.parse(GPGGA_Test);
System.out.println(nmea.position);