📄 nmea.java
字号:
/***********************************************************************
* J a v a G P S - GPS access library and Java API *
* Copyright (C) 2001 Ulrich Walther *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License for more details. *
* *
* You should have received a copy of the GNU General Public *
* License along with this program; if not, write to the Free *
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
* MA 02111-1307 USA *
***********************************************************************/
package org.iu.gps;
import java.lang.reflect.*;
/**
* NMEA0183 message parser. Uses reflection to be able to easily specify new
* NMEA messages (see below: sentenceDef).
*
*@author walther
*/
public class NMEA {
// Here are the definitions of GPS sentences we can handle
// Note: the argument names correspond to members of class GPSInfo and
// are automatically converted to the type of the members.
/**
* Definition of understood NMEA0183 sentences. The values given here as
* symbolic names are taken as field names of the info object given to the
* parse method; values from the sentence are automatically converted to the
* field's type in the info object. E.g. the definition of<br>
* <code>$GPTST,lat,long</code><br>
* specifies a new message that has the header <code>$GPTST</code>, and two
* parameters lat and long. Those two values are automatically parsed and
* stored inside the GPSInfo class, in the fields with names lat and long. The
* type of the value is automatically converted to fit the type of the fields.
*/
public final static String[] sentenceDef = new String[]{
"$GPGGA,utc,latitude,northHemi,longitude,eastHemi,quality," +
"numberOfSatellites,horDilution,height,,geoidalHeight,,diffCorrection,diffStationId,",
"$GPGSA,mode,fixtype,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12," +
"posDilution,horDilution,verDilution,",
"$GPGSV,gsvnum,gsvcur,satInView",
"$GPRMC,utc,status,latitude,northHemi,longitude,eastHemi," +
"speedOverGroundKnots,courseOverGround,utcdate,magnVariation,magnVarDirection,",
"$GPVTG,courseOverGround,,magnCourse,,speedOverGroundKnots,,speedOverGround,",
"$LCGLL,latitude,northHemi,longitude,eastHemi,utc,",
"$LCVTG,courseOverGround,,magnCourse,,speedOverGroundKnots,,speedOverGround,",
"$PGRME,HPE,,VPE,,EPE,",
"$PGRMF,GPSWeek,GPSSeconds,utcdate,utc,GPSLeapSecondCount," +
"latitude,northHemi,longitude,eastHemi,mode,fixType,speedOverGround,courseOverGround,",
"$PGRMT,GPSModel,romChecksum,recvFailure,storedDataLost,timeLost," +
"oscillatorDrift,dataCollection,boardTemperature,boardConfig",
"$PGRMV,eastVelocity,northVelocity,upVelocity,",
};
/**
* Parses a given NMEA0183 message (usually from GPS device) and automatically
* converts the parsed values to fit into the given info structure.
*
*@param sentence NMEA sentence to parse
*@param info Object to fill in values from sentence
*@return true if successful, false otherwise
*/
public static boolean parse( String sentence, GPSInfo info )
{
try
{
String type = sentence.substring( 0, 7 );
for ( int i = 0; i < sentenceDef.length; i++ )
{
if ( sentenceDef[i].startsWith( type ) )
{
parseSentence( sentence.substring( 7 ), sentenceDef[i].substring( 7 ), info );
return true;
}
}
}
catch (Exception e)
{
System.out.println("Cannot parse: "+sentence);
e.printStackTrace();
}
return false;
// System.out.println("Warning: sentence "+type+" not supported.");
}
/**
* Main method
*
*@param arg User arguments
*@throws Exception Throws all exeptions
*/
public static void main( String[] arg ) throws Exception
{
GPSInfo info = new GPSInfo();
parseSentence( "3,4,test,5", "longitude,latitude,utc,speedOverGround", info );
Class c = info.getClass();
Field[] f = c.getDeclaredFields();
for ( int i = 0; i < f.length; i++ )
{
System.out.println( f[i].getName() + ":" + f[i].getType() );
}
// f[0].set( info, "test" );
c.getField( "utc" ).set( info, "test2" );
System.out.println( info.utc );
}
// Increase all members of an object that end with "Age"
static void increaseAge( Object o )
{
Class c = o.getClass();
Field[] f = c.getFields();
for ( int i = 0; i < f.length; i++ )
{
if ( f[i].getName().endsWith( "Age" ) )
{
try
{
int age = f[i].getInt( o );
if ( age < 9999 )
{
f[i].setInt( o, age + 1 );
}
}
catch ( Exception e )
{
}
}
}
}
// Print all members of an object
static void printAll( Object o )
{
Class c = o.getClass();
Field[] f = c.getFields();
for ( int i = 0; i < f.length; i++ )
{
try
{
System.out.println( f[i].getName() + "=" + f[i].get( o ) );
}
catch ( Exception e )
{
}
}
}
// Set all members of an object that end with "Age" to -1 == inifite age
static void infiniteAge( Object o )
{
Class c = o.getClass();
Field[] f = c.getFields();
for ( int i = 0; i < f.length; i++ )
{
if ( f[i].getName().endsWith( "Age" ) )
{
try
{
f[i].setInt( o, 9999 );
}
catch ( Exception e )
{
}
}
}
}
static void parseSentence( String sentence, String syntax, Object result )
{
NMEATokenizer t = new NMEATokenizer( sentence );
NMEATokenizer t2 = new NMEATokenizer( syntax );
String s;
String s2;
Field f;
Field fage;
Class c = result.getClass();
while ( t.hasMoreTokens() && t2.hasMoreTokens() )
{
s = t.nextToken();
s2 = t2.nextToken();
if ( s.length() == 0 || s2.length() == 0 )
{
continue;
}
// System.out.print( s2+" = "+s);
try
{
f = c.getField( s2 );
}
catch ( NoSuchFieldException e )
{
// System.out.println(" *** "+e);
continue;
}
boolean gotValue = true;
try
{
String type = f.getType().getName();
if ( type.equals( "java.lang.String" ) )
{
f.set( result, s );
}
else
if ( type.equals( "byte" ) )
{
f.setByte( result, new Byte( s ).byteValue() );
}
else
if ( type.equals( "char" ) )
{
f.setChar( result, new String( s ).charAt( 0 ) );
}
else
if ( type.equals( "int" ) )
{
f.setInt( result, new Integer( s ).intValue() );
}
else
if ( type.equals( "float" ) )
{
f.setFloat( result, new Double( s ).floatValue() );
}
else
if ( type.equals( "double" ) )
{
f.setDouble( result, new Double( s ).doubleValue() );
}
else
{
System.out.println( "Warning: argument " + s2 + " cannot be converted to " + type );
gotValue = false;
}
}
catch ( Exception e )
{
// System.out.println(" *** "+e);
continue;
}
// reset age of the received value to zero
// (before reception of a value of that type,
// it remains at state -1 == infinite age)
if ( gotValue )
{
try
{
f = c.getField( s2 + "Age" );
f.setInt( result, 0 );
}
catch ( Exception e )
{
}
}
// System.out.println();
}
}
static String checkSum( String msg )
{
// perform NMEA checksum calculation
int chk = 0;
for ( int i = 1; i < msg.length(); i++ )
{
chk ^= msg.charAt( i );
}
String chk_s = Integer.toHexString( chk ).toUpperCase();
// checksum must be 2 characters!
while ( chk_s.length() < 2 )
{
chk_s = "0" + chk_s;
}
return chk_s;
}
// calculate checksum of NMEA message and compare
static boolean check( String msg )
{
int msglen = msg.length();
if ( msglen > 4 )
{
if ( msg.charAt( msglen - 3 ) == '*' )
{
// perform NMEA checksum calculation
String chk_s = checkSum( msg.substring( 0, msglen - 3 ) );
// compare checksum to encoded checksum in msg
return ( msg.substring( msglen - 2, msglen ).equals( chk_s ) );
}
else
{
// message doesn't have a checksum: accept it
return true;
}
}
// don't accept messages without checksum
return false;
}
static String addCheckSum( String msg )
{
return msg + "," + checkSum( msg + "," ) + "*" + ( ( char ) 13 ) + ( ( char ) 10 );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -