Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69d41a00 authored by Mike Lockwood's avatar Mike Lockwood Committed by Android (Google) Code Review
Browse files

Merge "Remove unused file NmeaParser.java"

parents b9e2719c 69d63446
Loading
Loading
Loading
Loading
+0 −437
Original line number Diff line number Diff line
/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.location;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;

import android.location.Location;
import android.os.Bundle;
import android.util.Log;

/**
 * {@hide}
 */
public class NmeaParser {

    private static final String TAG = "NmeaParser";

    private static final TimeZone sUtcTimeZone = TimeZone.getTimeZone("UTC");

    private static final float KNOTS_TO_METERS_PER_SECOND = 0.51444444444f;

    private final String mName;

    private int mYear = -1;
    private int mMonth;
    private int mDay;

    private long mTime = -1;
    private long mBaseTime;
    private double mLatitude;
    private double mLongitude;

    private boolean mHasAltitude;
    private double mAltitude;
    private boolean mHasBearing;
    private float mBearing;
    private boolean mHasSpeed;
    private float mSpeed;

    private boolean mNewWaypoint = false;
    private Location mLocation = null;
    private Bundle mExtras;

    public NmeaParser(String name) {
        mName = name;
    }

    private boolean updateTime(String time) {
        if (time.length() < 6) {
            return false;
        }
        if (mYear == -1) {
            // Since we haven't seen a day/month/year yet,
            // we can't construct a meaningful time stamp.
            // Clean up any old data.
            mLatitude = 0.0;
            mLongitude = 0.0;
            mHasAltitude = false;
            mHasBearing = false;
            mHasSpeed = false;
            mExtras = null;
            return false;
        }

        int hour, minute;
        float second;
        try {
            hour = Integer.parseInt(time.substring(0, 2));
            minute = Integer.parseInt(time.substring(2, 4));
            second = Float.parseFloat(time.substring(4, time.length()));
        } catch (NumberFormatException nfe) {
            Log.e(TAG, "Error parsing timestamp " + time);
            return false;
        }

        int isecond = (int) second;
        int millis = (int) ((second - isecond) * 1000);
        Calendar c = new GregorianCalendar(sUtcTimeZone);
        c.set(mYear, mMonth, mDay, hour, minute, isecond);
        long newTime = c.getTimeInMillis() + millis;

        if (mTime == -1) {
            mTime = 0;
            mBaseTime = newTime;
        }
        newTime -= mBaseTime;

        // If the timestamp has advanced, copy the temporary data
        // into a new Location
        if (newTime != mTime) {
            mNewWaypoint = true;
            mLocation = new Location(mName);
            mLocation.setTime(mTime);
            mLocation.setLatitude(mLatitude);
            mLocation.setLongitude(mLongitude);
            if (mHasAltitude) {
                mLocation.setAltitude(mAltitude);
            }
            if (mHasBearing) {
                mLocation.setBearing(mBearing);
            }
            if (mHasSpeed) {
                mLocation.setSpeed(mSpeed);
            }
            mLocation.setExtras(mExtras);
            mExtras = null;

            mTime = newTime;
            mHasAltitude = false;
            mHasBearing = false;
            mHasSpeed = false;
        }
        return true;
    }

    private boolean updateDate(String date) {
        if (date.length() != 6) {
            return false;
        }
        int month, day, year;
        try {
            day = Integer.parseInt(date.substring(0, 2));
            month = Integer.parseInt(date.substring(2, 4));
            year = 2000 + Integer.parseInt(date.substring(4, 6));
        } catch (NumberFormatException nfe) {
            Log.e(TAG, "Error parsing date " + date);
            return false;
        }

        mYear = year;
        mMonth = month;
        mDay = day;
        return true;
    }

    private boolean updateTime(String time, String date) {
        if (!updateDate(date)) {
                return false;
        }
        return updateTime(time);
    }

    private boolean updateIntExtra(String name, String value) {
        int val;
        try {
            val = Integer.parseInt(value);
        } catch (NumberFormatException nfe) {
            Log.e(TAG, "Exception parsing int " + name + ": " + value, nfe);
            return false;
        }
        if (mExtras == null) {
            mExtras = new Bundle();
        }
        mExtras.putInt(name, val);
        return true;
    }

    private boolean updateFloatExtra(String name, String value) {
        float val;
        try {
            val = Float.parseFloat(value);
        } catch (NumberFormatException nfe) {
            Log.e(TAG, "Exception parsing float " + name + ": " + value, nfe);
            return false;
        }
        if (mExtras == null) {
            mExtras = new Bundle();
        }
        mExtras.putFloat(name, val);
        return true;
    }

    private boolean updateDoubleExtra(String name, String value) {
        double val;
        try {
            val = Double.parseDouble(value);
        } catch (NumberFormatException nfe) {
            Log.e(TAG, "Exception parsing double " + name + ": " + value, nfe);
            return false;
        }
        if (mExtras == null) {
            mExtras = new Bundle();
        }
        mExtras.putDouble(name, val);
        return true;
    }

    private double convertFromHHMM(String coord) {
        double val = Double.parseDouble(coord);
        int degrees = ((int) Math.floor(val)) / 100;
        double minutes = val - (degrees * 100);
        double dcoord = degrees + minutes / 60.0;
        return dcoord;
    }

    private boolean updateLatLon(String latitude, String latitudeHemi,
        String longitude, String longitudeHemi) {
        if (latitude.length() == 0 || longitude.length() == 0) {
            return false;
        }

        // Lat/long values are expressed as {D}DDMM.MMMM
        double lat, lon;
        try {
            lat = convertFromHHMM(latitude);
            if (latitudeHemi.charAt(0) == 'S') {
                lat = -lat;
            }
        } catch (NumberFormatException nfe1) {
            Log.e(TAG, "Exception parsing lat/long: " + nfe1, nfe1);
            return false;
        }

        try {
            lon = convertFromHHMM(longitude);
            if (longitudeHemi.charAt(0) == 'W') {
                lon = -lon;
            }
        } catch (NumberFormatException nfe2) {
            Log.e(TAG, "Exception parsing lat/long: " + nfe2, nfe2);
            return false;
        }

        // Only update if both were parsed cleanly
        mLatitude = lat;
        mLongitude = lon;
        return true;
    }

    private boolean updateAltitude(String altitude) {
        if (altitude.length() == 0) {
            return false;
        }
        double alt;
        try {
            alt = Double.parseDouble(altitude);
        } catch (NumberFormatException nfe) {
            Log.e(TAG, "Exception parsing altitude " + altitude + ": " + nfe,
                  nfe);
            return false;
        }

        mHasAltitude = true;
        mAltitude = alt;
        return true;
    }

    private boolean updateBearing(String bearing) {
        float brg;
        try {
            brg = Float.parseFloat(bearing);
        } catch (NumberFormatException nfe) {
            Log.e(TAG, "Exception parsing bearing " + bearing + ": " + nfe,
                  nfe);
            return false;
        }

        mHasBearing = true;
        mBearing = brg;
        return true;
    }

    private boolean updateSpeed(String speed) {
        float spd;
        try {
            spd = Float.parseFloat(speed) * KNOTS_TO_METERS_PER_SECOND;
        } catch (NumberFormatException nfe) {
            Log.e(TAG, "Exception parsing speed " + speed + ": " + nfe, nfe);
            return false;
        }

        mHasSpeed = true;
        mSpeed = spd;
        return true;
    }

    public boolean parseSentence(String s) {
        int len = s.length();
        if (len < 9) {
            return false;
        }
        if (s.charAt(len - 3) == '*') {
            // String checksum = s.substring(len - 4, len);
            s = s.substring(0, len - 3);
        }
        String[] tokens = s.split(",");
        String sentenceId = tokens[0].substring(3, 6);

        int idx = 1;
        try {
            if (sentenceId.equals("GGA")) {
                String time = tokens[idx++];
                String latitude = tokens[idx++];
                String latitudeHemi = tokens[idx++];
                String longitude = tokens[idx++];
                String longitudeHemi = tokens[idx++];
                String fixQuality = tokens[idx++];
                String numSatellites = tokens[idx++];
                String horizontalDilutionOfPrecision = tokens[idx++];
                String altitude = tokens[idx++];
                String altitudeUnits = tokens[idx++];
                String heightOfGeoid = tokens[idx++];
                String heightOfGeoidUnits = tokens[idx++];
                String timeSinceLastDgpsUpdate = tokens[idx++];

                updateTime(time);
                updateLatLon(latitude, latitudeHemi,
                        longitude, longitudeHemi);
                updateAltitude(altitude);
                // updateQuality(fixQuality);
                updateIntExtra("numSatellites", numSatellites);
                updateFloatExtra("hdop", horizontalDilutionOfPrecision);

                if (mNewWaypoint) {
                    mNewWaypoint = false;
                    return true;
                }
            } else if (sentenceId.equals("GSA")) {
                // DOP and active satellites
                String selectionMode = tokens[idx++]; // m=manual, a=auto 2d/3d
                String mode = tokens[idx++]; // 1=no fix, 2=2d, 3=3d
                for (int i = 0; i < 12; i++) {
                    String id = tokens[idx++];
                }
                String pdop = tokens[idx++];
                String hdop = tokens[idx++];
                String vdop = tokens[idx++];

                // TODO - publish satellite ids
                updateFloatExtra("pdop", pdop);
                updateFloatExtra("hdop", hdop);
                updateFloatExtra("vdop", vdop);
            } else if (sentenceId.equals("GSV")) {
                // Satellites in view
                String numMessages = tokens[idx++];
                String messageNum = tokens[idx++];
                String svsInView = tokens[idx++];
                for (int i = 0; i < 4; i++) {
                    if (idx + 2 < tokens.length) {
                        String prnNumber = tokens[idx++];
                        String elevation = tokens[idx++];
                        String azimuth = tokens[idx++];
                        if (idx < tokens.length) {
                            String snr = tokens[idx++];
                        }
                    }
                }
                // TODO - publish this info
            } else if (sentenceId.equals("RMC")) {
                // Recommended minimum navigation information
                String time = tokens[idx++];
                String fixStatus = tokens[idx++];
                String latitude = tokens[idx++];
                String latitudeHemi = tokens[idx++];
                String longitude = tokens[idx++];
                String longitudeHemi = tokens[idx++];
                String speed = tokens[idx++];
                String bearing = tokens[idx++];
                String utcDate = tokens[idx++];
                String magneticVariation = tokens[idx++];
                String magneticVariationDir = tokens[idx++];
                String mode = tokens[idx++];

                if (fixStatus.charAt(0) == 'A') {
                    updateTime(time, utcDate);
                    updateLatLon(latitude, latitudeHemi,
                        longitude, longitudeHemi);
                    updateBearing(bearing);
                    updateSpeed(speed);
                }

                if (mNewWaypoint) {
                    return true;
                }
            } else {
                Log.e(TAG, "Unknown sentence: " + s);
            }
        } catch (ArrayIndexOutOfBoundsException e) {
            // do nothing - sentence will have no effect
            Log.e(TAG, "AIOOBE", e);

            for (int i = 0; i < tokens.length; i++) {
                Log.e(TAG, "Got token #" + i + " = " + tokens[i]);
            }
        }

        return false;
    }

//  } else if (sentenceId.equals("GLL")) {
//  // Geographics position lat/long
//  String latitude = tokens[idx++];
//  String latitudeHemi = tokens[idx++];
//  String longitude = tokens[idx++];
//  String longitudeHemi = tokens[idx++];
//  String time = tokens[idx++];
//  String status = tokens[idx++];
//  String mode = tokens[idx++];
//  String checksum = tokens[idx++];
//
//  if (status.charAt(0) == 'A') {
//      updateTime(time);
//      updateLatLon(latitude, latitudeHemi, longitude, longitudeHemi);
//  }
//} else if (sentenceId.equals("VTG")) {
//    String trackMadeGood = tokens[idx++];
//    String t = tokens[idx++];
//    String unused1 = tokens[idx++];
//    String unused2 = tokens[idx++];
//    String groundSpeedKnots = tokens[idx++];
//    String n = tokens[idx++];
//    String groundSpeedKph = tokens[idx++];
//    String k = tokens[idx++];
//    String checksum = tokens[idx++];
//
//    updateSpeed(groundSpeedKph);

    public Location getLocation() {
        return mLocation;
    }
}