org.loklak.api.iot.NMEAServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.loklak.api.iot.NMEAServlet.java

Source

/**
 *  NMEA Servlet
 *  Copyright 02.07.2016 by Sudheesh Singanamalla, @sudheesh001
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *  
 *  This library 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
 *  Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program in the file lgpl21.txt
 *  If not, see <http://www.gnu.org/licenses/>.
 */

package org.loklak.api.iot;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

import java.net.*;
import java.io.*;

import org.json.JSONObject;
import org.loklak.server.Query;
import org.loklak.http.RemoteAccess;

/*
Sample Read Format
==================
  1      2    3        4 5         6 7     8     9      10    11
$xxxxx,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
  |      |    |        | |         | |     |     |      |     |
  |      |    |        | |         | |     |     |      |     Variation sign
  |      |    |        | |         | |     |     |      Variation value
  |      |    |        | |         | |     |     Date DDMMYY
  |      |    |        | |         | |     COG
  |      |    |        | |         | SOG
  |      |    |        | |         Longitude Sign
  |      |    |        | Longitude Value
  |      |    |        Latitude Sign
  |      |    Latitude value
  |      Active or Void
  UTC HHMMSS
 */
public class NMEAServlet extends HttpServlet {

    interface SentenceParser {
        public boolean parse(String[] tokens, GPSPosition position);
    }

    // utilities for conversion of minute based latitutde and longitude data
    // from GPS Chips to lat longitudes
    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 for different type of GPS record sentences.
    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;
        }
    }

    // Add a new parser format here.

    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 JSONObject toJSONString() {
            JSONObject rJsonObject = new JSONObject(true);
            rJsonObject.put("lat", lat);
            rJsonObject.put("long", lon);
            rJsonObject.put("time", time);
            rJsonObject.put("Q", quality);
            rJsonObject.put("dir", dir);
            rJsonObject.put("alt", altitude);
            rJsonObject.put("vel", velocity);
            return rJsonObject;
        }

        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 NMEAServlet() {
        sentenceParsers.put("GPGGA", new GPGGA());
        sentenceParsers.put("GPGGL", new GPGGL());
        sentenceParsers.put("GPRMC", new GPRMC());
        sentenceParsers.put("GPRMZ", new GPRMZ());
        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;
    }

    // Object Response Structure
    // -------------------------
    // { "idNumbers" : { "lat", "long", "time" , "Q", "dir", "alt", "vel" } , ... }
    // -------------------------
    /* Sample Response
       {
    "1": {
      "lat": 60.073490142822266,
      "long": 19.67548179626465,
      "time": 94154,
      "Q": 2,
      "dir": 82.0999984741211,
      "alt": 0.699999988079071,
      "vel": 1.7999999523162842
    },
    "2": {
      "lat": 60.07347106933594,
      "long": 19.675262451171875,
      "time": 94140,
      "Q": 2,
      "dir": 82.0999984741211,
      "alt": 0.10000000149011612,
      "vel": 1.7999999523162842
    }
       }
    */

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        Query post = RemoteAccess.evaluate(request);

        // Sample usage for each line of NMEA Sentence data
        // GPSPosition a = new GPSPosition();
        // a = parse("$GPGGA,220550,4124.7580,N,08152.2565,W,2,04,4.4,235.1,M,-34.0,M,,*7B");

        if (post.isDoS_blackout()) {
            response.sendError(503, "your request frequency is too high");
            return;
        }

        // Send the stream URL as stream parameter.
        String stream = post.get("stream", "");
        String minified = post.get("minified", "");

        // Download the file/Stream of NMEA data as a buffered stream.
        URL url = new URL(stream);
        BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
        String NMEALine;

        JSONObject json = new JSONObject(true);
        int lines = 0;

        // Read each buffered stream line by line and parse and convert NMEA to an actual object.
        while ((NMEALine = in.readLine()) != null) {
            lines++;
            GPSPosition gpsObject = new GPSPosition();
            gpsObject = parse(NMEALine);
            json.put(String.valueOf(lines), gpsObject.toJSONString());
        }

        in.close();

        // Start the printwriter and get ready to respond with json
        PrintWriter sos = response.getWriter();
        if (minified != "true") {
            sos.print(json.toString(2));
        } else {
            sos.print(json.toString());
        }
        sos.println();

        post.finalize();
    }

}