aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/traccar/helper/NMEA.java126
-rw-r--r--src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java83
2 files changed, 209 insertions, 0 deletions
diff --git a/src/main/java/org/traccar/helper/NMEA.java b/src/main/java/org/traccar/helper/NMEA.java
new file mode 100644
index 000000000..cae47a8f6
--- /dev/null
+++ b/src/main/java/org/traccar/helper/NMEA.java
@@ -0,0 +1,126 @@
+package org.traccar.helper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class NMEA {
+
+ // fucking java interfaces
+ 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;
+ }
+}
diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java
index 244df6806..6ca9b0795 100644
--- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java
@@ -21,20 +21,27 @@ import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.QueryStringDecoder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.traccar.BaseHttpProtocolDecoder;
+import org.traccar.WebDataHandler;
import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
+import org.traccar.helper.NMEA;
import org.traccar.model.Position;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
+import java.util.Date;
import java.util.LinkedList;
import java.util.List;
public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder {
+ private static final Logger LOGGER = LoggerFactory.getLogger(WebDataHandler.class);
+
public PiligrimProtocolDecoder(Protocol protocol) {
super(protocol);
}
@@ -150,6 +157,82 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder {
}
return positions;
+ } else if (uri.startsWith("/push.do")) {
+ sendResponse(channel, "PUSH.DO: OK");
+
+ /* Getting payload */
+ ByteBuf contentStream = request.content();
+ byte[] payloadBytes = new byte[Integer.parseInt(request.headers().get("Content-Length"))];
+ contentStream.readBytes(payloadBytes);
+ String payload = new String(payloadBytes);
+
+ /* Payload structure:
+ * &phone&message
+ */
+ String[] payloadParts = payload.split("&");
+ /* LOGGER.debug("Payload parts: " + Arrays.toString(payloadParts)); */
+ String phoneNumber = payloadParts[1].substring(15);
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, phoneNumber.substring(1));
+ if (deviceSession == null) {
+ return null;
+ }
+
+ /* TODO: use keys for flags in 'positions'. */
+ String message = payloadParts[2].substring(8).replaceFirst("[a-zA-Z! ]*; ", "");
+ /* LOGGER.debug("Phone number: " + phoneNumber); */
+ /* LOGGER.debug("Message: " + message); */
+
+ if (message.startsWith("$GPRMC")) {
+ /* Supported message structure:
+ * GPS NMEA Command; GSM info; Unknown; Battery voltage?
+ * Example: $GPRMC,180752.000,A,5314.0857,N,03421.8173,E,0.00,104.74,220722,,,A,V* 29,05; GSM: 250-01 0b54-0519,1c30,3e96,3ebe,412e 25; S; Batt: 405,M
+ */
+ LOGGER.debug("Supported message");
+
+ String[] messageParts = message.split(";");
+ /* LOGGER.debug("Message parts: " + Arrays.toString(messageParts)); */
+
+ /* Parsing GPS */
+ String unprocessedGpsCommand = messageParts[0];
+
+ /* Getting rid of checksum */
+ String gpsCommand = unprocessedGpsCommand.replaceFirst("A,V[*].*", "");
+ /* LOGGER.debug("GPS command: " + gpsCommand); */
+
+ NMEA gpsParser = new NMEA();
+
+ NMEA.GPSPosition gpsPosition = gpsParser.parse(gpsCommand);
+
+ /* LOGGER.debug("Time: " + gpsPosition.time); */
+ /* LOGGER.debug("Coordinates: " + gpsPosition.lat + " " + gpsPosition.lon); */
+ /* LOGGER.debug("Speed over ground: " + gpsPosition.velocity + " knots"); */
+
+ /* Parsing other fields */
+ /* String gsmInfo = messageParts[1]; */
+ /* String unknown = messageParts[2]; */
+ String batteryInfo = messageParts[messageParts.length - 1].substring(7).substring(0, 3);
+ /* LOGGER.debug("Battery: " + batteryInfo); */
+
+ /* Constructing response */
+ Position position = new Position(getProtocolName());
+
+ position.setDeviceId(deviceSession.getDeviceId());
+ position.setValid(true);
+ position.setLatitude(gpsPosition.lat);
+ position.setLongitude(gpsPosition.lon);
+ position.setTime(new Date(System.currentTimeMillis()));
+ position.setSpeed(gpsPosition.velocity);
+ position.setCourse(gpsPosition.dir);
+ position.setAccuracy(gpsPosition.quality);
+ position.setAltitude(gpsPosition.altitude);
+ position.set(Position.KEY_BATTERY, Integer.parseInt(batteryInfo) / 100);
+
+ LOGGER.debug("Supported message finish");
+
+ return position;
+ } else {
+ LOGGER.error("Unsupported message");
+ }
}
return null;