Package com.mapmidlet.gps

Source Code of com.mapmidlet.gps.GpsConnection

/*
* 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; version 3 of the License.
*
* 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.
*
* Author: Damian Waradzyn
*/
package com.mapmidlet.gps;

import java.io.*;
import java.util.*;

import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;

import com.mapmidlet.CloudGps;
import com.mapmidlet.misc.*;
import com.mapmidlet.options.Options;
import com.mapmidlet.projection.WorldCoordinate;

/**
* This class is responsible for maintaining connection with GPS device or NMEA
* log file. In a separate thread it read and parses NMEA sentences writing
* results to GpsState.
*
* @author Damian Waradzyn
*/
public class GpsConnection {

    private InputStream inputStream = null;
    private final GpsState gpsState;

    private boolean exit;

    private DataOutputStream logOutput = null;

    public GpsConnection(GpsState gpsState) {
        this.gpsState = gpsState;
    }

    public void open() throws IOException {

        thread = new Thread(new Runnable() {
            public void run() {
                exit = false;
                Options options = Options.getInstance();
                int tries = 0;
                while (inputStream == null) {
                    try {
                        if (options.replayMode) {
                            inputStream = Connector.openInputStream(options.replayFileName);
                            FileConnection conn = (FileConnection) Connector.open(options.replayFileName,
                                    Connector.READ);
                            gpsState.replySize = conn.fileSize();
                            gpsState.replyPosition = 0;
                            conn.close();
                        } else {
                            inputStream = Connector.openInputStream(options.gpsUrl);
                        }
                    } catch (Throwable e) {
                        tries++;
                        CloudGps.setError(e);
                        e.printStackTrace();

                        if (tries >= 3) {
                            gpsState.state = GpsState.CONNECTION_ERROR;
                            throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage());
                        }

                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException ie) {
                            ie.printStackTrace();
                        }
                    }
                }

                if (options.replayMode) {
                    logOutput = null;
                } else {
                    IOTool.ensureDirExist(IOTool.NMEA_LOGS_DIR);
                    logOutput = IOTool.createLogFile();
                }

                gpsState.state = GpsState.CONNECTED_NO_FIX;
                String line;
                int length, idx1;
                byte[] buf;
                byte[] buff = new byte[512];
                StringBuffer tmp = new StringBuffer(256);

                while (!exit) {
                    try {
                        if (inputStream == null) {
                            return;
                        }
                        if (inputStream.available() > 0 || options.replayMode) {
                            length = inputStream.read(buff, 0, buff.length);
                            if (length < 0) {
                                close();
                                if (options.replayMode) {
                                    options.replayMode = false;
                                }
                                return;
                            }

                            if (options.replayMode) {
                                gpsState.replyPosition += length;
                            }

                            if (length < buff.length) {
                                buf = new byte[length];
                                System.arraycopy(buff, 0, buf, 0, length);
                                tmp.append(new String(buf));
                            } else {
                                tmp.append(new String(buff));
                            }
                            idx1 = tmp.toString().indexOf("\r\n");
                            while (idx1 >= 0) {
                                line = tmp.toString().substring(0, idx1);
                                try {
                                    if (logOutput != null) {
                                        logOutput.write(line.getBytes());
                                        logOutput.write("\r\n".getBytes());
                                    }
                                    parseNmea(line);

                                    if (options.replayMode && line.length() > 6 && "GPRMC".equals(line.substring(1, 6))) {
                                        try {
                                            Thread.sleep(1000 / options.replaySpeed);
                                        } catch (InterruptedException ie) {
                                        }
                                    }
                                } catch (Throwable e) {
                                    e.printStackTrace();
                                    CloudGps.setError(e);
                                }

                                tmp = new StringBuffer(tmp.toString().substring(idx1 + 2));
                                idx1 = tmp.toString().indexOf("\r\n");
                            }
                        } else {
                            Thread.yield();
                        }
                    } catch (Throwable e) {
                        CloudGps.setError(e);
                    }
                }
            }
        });
        thread.start();

    }

    public void close() {
        gpsState.state = GpsState.CONNECTING;
        if (thread != null) {
            exit = true;
            if (!Thread.currentThread().equals(thread)) {
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            thread = null;
        }
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                CloudGps.setError(e);
            }
        }
        inputStream = null;
        if (logOutput != null) {
            try {
                logOutput.close();
            } catch (IOException e) {
                CloudGps.setError(e);
            }
            logOutput = null;
        }
    }

    public InputStream getInputStream() {
        return inputStream;
    }

    /**
     * Parsing NMEA - see http://home.mira.net/~gnb/gps/nmea.html
     *
     * @param nmea
     */
    public void parseNmea(String nmea) {
        if (Options.getInstance().debugMode) {
            System.out.println(nmea);
        }
        if (nmea.length() < 9 || !nmea.startsWith("$")) {
            System.out.println("invalid nmea sentence: '" + nmea + "'");
            return;
        }
        String msgType = nmea.substring(1, 6);

        if ("GPRMC".equals(msgType)) {
            parseRmc(nmea);
        } else if ("GPVTG".equals(msgType)) {
            parseVtg(nmea);
        } else if ("GPGSA".equals(msgType)) {
            parseGsa(nmea);
        } else if ("GPGSV".equals(msgType)) {
            parseGsv(nmea);
        } else if ("GPGGA".equals(msgType)) {
            parseGga(nmea);
        }

    }

    private void parseVtg(String nmea) {
        String[] strings = StringTool.tokenize(nmea, ',');
        if ("".equals(strings[7])) {
            gpsState.state = GpsState.CONNECTED_NO_FIX;
        } else {
            if (!"".equals(strings[1]) && !"nan".equals(strings[1])) {
                gpsState.compass = Double.parseDouble(strings[1]);
            } else {
                gpsState.compass = -1;
            }
            gpsState.groundSpeed = Double.parseDouble(strings[7]);
        }
    }

    private void parseRmc(String nmea) {
        String[] strings = StringTool.tokenize(nmea, ',');
        if ("A".equals(strings[2])) {
            gpsState.time = strings[1];
            setCoordinates(strings, 3);
            gpsState.state = GpsState.CONNECTED_FIX;

            // conversion between knots and kmph
            if (!"".equals(strings[7])) {
                gpsState.groundSpeed = Double.parseDouble(strings[7]) * 1.852;
            } else {
                gpsState.groundSpeed = -1;
            }
            if (!"".equals(strings[8])) {
                try {
                    gpsState.compass = Double.parseDouble(strings[8]);
                } catch (NumberFormatException nfe) {
                    gpsState.compass = -1;
                }
            } else {
                gpsState.compass = -1;
            }
        } else {
            gpsState.state = GpsState.CONNECTED_NO_FIX;
        }
    }

    private void setCoordinates(String[] strings, int i) {

        if (gpsState.worldCoordinate == null) {
            gpsState.worldCoordinate = new WorldCoordinate();
        } else {
            if (gpsState.prevWorldCoordinate == null) {
                gpsState.prevWorldCoordinate = new WorldCoordinate();
            }
            gpsState.prevWorldCoordinate.latitude = gpsState.worldCoordinate.latitude;
            gpsState.prevWorldCoordinate.longitude = gpsState.worldCoordinate.longitude;
        }
        if ("N".equals(strings[i + 1])) {
            gpsState.worldCoordinate.latitude = getCoordinate(strings[i]);
        } else {
            gpsState.worldCoordinate.latitude = -getCoordinate(strings[i]);
        }

        if ("E".equals(strings[i + 3])) {
            gpsState.worldCoordinate.longitude = getCoordinate(strings[i + 2]);
        } else {
            gpsState.worldCoordinate.longitude = -getCoordinate(strings[i + 2]);
        }
        gpsState.prevCoordinateUpdateMilis = gpsState.coordinateUpdateMilis;
        gpsState.coordinateUpdateMilis = System.currentTimeMillis();
    }

    Vector satellites;
    Hashtable activeSats;
    private Thread thread;

    private void parseGga(String nmea) {
        String[] strings = StringTool.tokenize(nmea, ',');
        gpsState.time = strings[1];
        if (strings[3].length() > 0) {
            // gpsState.state = GpsState.CONNECTED_FIX_3D;
            // setCoordinates(strings, 2);
            gpsState.altitude = Double.parseDouble(strings[9]);
        }
    }

    private double getCoordinate(String string) {
        // string = 5005.075330
        // result = 50 + 05.075330 * 100.0 / 60.0

        double tmp = Double.parseDouble(string);

        double d = tmp / 100.0;
        double floor = Math.floor(d);
        return floor + (d - floor) * 5.0 / 3.0;
    }

    private void parseGsv(String nmea) {
        String[] strings = StringTool.tokenize(nmea, ',');

        if (strings[2].equals("1")) {
            satellites = new Vector(24);
        }

        gpsState.satellitesInView = Integer.parseInt(strings[3]);

        int max;
        if (strings[1].equals(strings[2])) {
            max = Integer.parseInt(strings[3]) - (Integer.parseInt(strings[2]) - 1) * 4;
        } else {
            max = 4;
        }
        for (int i = 1; i <= max; i++) {
            int baseIndex = i * 4;
            if (strings[baseIndex].equals("")) {
                break;
            }

            GpsState.Satellite satellite = new GpsState.Satellite();
            satellite.prn = strings[baseIndex];
            if (strings[baseIndex + 3].length() > 0) {
                if (i == max) {
                    String s;
                    int tmp = strings[baseIndex + 3].indexOf('*');
                    if (tmp >= 0) {
                        s = strings[baseIndex + 3].substring(0, tmp);
                    } else {
                        s = strings[baseIndex + 3];
                    }
                    if (s.length() > 0) {
                        satellite.snr = Integer.parseInt(s);
                    } else {
                        satellite.snr = -1;
                    }
                } else {
                    satellite.snr = Integer.parseInt(strings[baseIndex + 3]);
                }
            } else {
                satellite.snr = -1;
            }
            satellites.addElement(satellite);
        }
        if (strings[1].equals(strings[2])) {
            gpsState.satellites = satellites;
        }
    }

    private void parseGsa(String nmea) {
        String[] strings = StringTool.tokenize(nmea, ',');

        // if (strings[2].charAt(0) == '1') {
        // gpsState.state = GpsState.CONNECTED_NO_FIX;
        // } else {
        // gpsState.state = GpsState.CONNECTED_FIX;
        // }
        activeSats = new Hashtable();
        for (int i = 3; i < 13; i++) {
            if ("".equals(strings[i])) {
                break;
            }
            activeSats.put(strings[i], strings[i]);
        }
        gpsState.activeSats = activeSats;
    }
}
TOP

Related Classes of com.mapmidlet.gps.GpsConnection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.