diff options
Diffstat (limited to 'src/main')
-rw-r--r-- | src/main/java/org/traccar/helper/NMEA.java | 126 | ||||
-rw-r--r-- | src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java | 83 |
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; |