From da76f9195ec6fbf0e6a0a6419eec908b91f844b7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 17 Oct 2015 13:09:05 +1300 Subject: Refactor GPS103 protocol decoder --- src/org/traccar/helper/DateBuilder.java | 5 + src/org/traccar/helper/Parser.java | 14 +- src/org/traccar/helper/PatternBuilder.java | 4 + .../traccar/protocol/Gps103ProtocolDecoder.java | 185 ++++++++------------- 4 files changed, 86 insertions(+), 122 deletions(-) (limited to 'src') diff --git a/src/org/traccar/helper/DateBuilder.java b/src/org/traccar/helper/DateBuilder.java index 9a75d90fc..5d2ee8e0a 100644 --- a/src/org/traccar/helper/DateBuilder.java +++ b/src/org/traccar/helper/DateBuilder.java @@ -84,6 +84,11 @@ public class DateBuilder { return this; } + public DateBuilder addMinute(int minute) { + calendar.add(Calendar.MINUTE, minute); + return this; + } + public DateBuilder setSecond(int second) { calendar.set(Calendar.SECOND, second); return this; diff --git a/src/org/traccar/helper/Parser.java b/src/org/traccar/helper/Parser.java index 107ae7bff..7694a9623 100644 --- a/src/org/traccar/helper/Parser.java +++ b/src/org/traccar/helper/Parser.java @@ -80,7 +80,8 @@ public class Parser { public enum CoordinateFormat { DEG_MIN_HEM, - HEM_DEG + HEM_DEG, + HEM_DEG_MIN_HEM } public double nextCoordinate(CoordinateFormat format) { @@ -92,9 +93,16 @@ public class Parser { hemisphere = next(); coordinate = nextDouble(); break; - case DEG_MIN_HEM: + case HEM_DEG_MIN_HEM: + hemisphere = next(); + coordinate = nextInt(); + coordinate += nextDouble() / 60; + if (hasNext()) { + hemisphere = next(); + } + break; default: - coordinate = nextDouble(); + coordinate = nextInt(); coordinate += nextDouble() / 60; hemisphere = next(); break; diff --git a/src/org/traccar/helper/PatternBuilder.java b/src/org/traccar/helper/PatternBuilder.java index fbef144e6..a0e24e017 100644 --- a/src/org/traccar/helper/PatternBuilder.java +++ b/src/org/traccar/helper/PatternBuilder.java @@ -82,6 +82,10 @@ public class PatternBuilder { } } + public PatternBuilder or() { + return xpr("|"); + } + public Pattern compile() { return Pattern.compile(pattern.toString(), Pattern.DOTALL); } diff --git a/src/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/org/traccar/protocol/Gps103ProtocolDecoder.java index 928c24e12..9bd508e92 100644 --- a/src/org/traccar/protocol/Gps103ProtocolDecoder.java +++ b/src/org/traccar/protocol/Gps103ProtocolDecoder.java @@ -16,12 +16,12 @@ package org.traccar.protocol; import java.net.SocketAddress; -import java.util.Calendar; -import java.util.TimeZone; -import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jboss.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; import org.traccar.model.Event; import org.traccar.model.Position; @@ -31,34 +31,41 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder { super(protocol); } - private static final Pattern PATTERN = Pattern.compile( - "imei:" + - "(\\d+)," + // IMEI - "([^,]+)," + // Alarm - "(\\d{2})/?(\\d{2})/?(\\d{2})\\s?" + // Local Date - "(\\d{2}):?(\\d{2})(?:\\d{2})?," + // Local Time - "[^,]*," + - "[FL]," + // F - full / L - low - "(?:(\\d{2})(\\d{2})(\\d{2})\\.(\\d+)|" + // Time UTC (HHMMSS.SSS) - "(?:\\d{1,5}\\.\\d+))," + - "([AV])," + // Validity - "(?:([NS]),)?" + - "(\\d+)(\\d{2}\\.\\d+)," + // Latitude (DDMM.MMMM) - "(?:([NS]),)?" + - "(?:([EW]),)?" + - "(\\d+)(\\d{2}\\.\\d+)," + // Longitude (DDDMM.MMMM) - "(?:([EW])?,)?" + - "(\\d+\\.?\\d*)?,?" + // Speed - "(\\d+\\.?\\d*)?,?" + // Course - "(\\d+\\.?\\d*)?,?" + // Altitude - "([^,;]+)?,?" + - "([^,;]+)?,?" + - "([^,;]+)?,?" + - "([^,;]+)?,?" + - "([^,;]+)?,?" + - ".*"); - - private static final Pattern PATTERN_HANDSHAKE = Pattern.compile("##,imei:(\\d+),A"); + private static final Pattern PATTERN = new PatternBuilder() + .txt("imei:") + .num("(d+),") // imei + .xpr("([^,]+),") // alarm + .num("(dd)/?(dd)/?(dd) ?") // local date + .num("(dd):?(dd)(?:dd)?,") // local time + .nxt(",") + .xpr("[FL],") // full / low + .groupBegin() + .num("(dd)(dd)(dd).(d+)") // time utc (hhmmss.sss) + .or() + .opn("d{1,5}.d+") + .groupEnd(false) + .txt(",") + .xpr("([AV]),") // validity + .opx("([NS]),") + .num("(d+)(dd.d+),") // latitude (ddmm.mmmm) + .opx("([NS]),") + .opx("([EW]),") + .num("(d+)(dd.d+),") // longitude (dddmm.mmmm) + .opx("([EW])?,") + .num("(d+.?d*)?,?") // speed + .num("(d+.?d*)?,?") // course + .num("(d+.?d*)?,?") // altitude + .xpr("([^,;]+)?,?") + .xpr("([^,;]+)?,?") + .xpr("([^,;]+)?,?") + .xpr("([^,;]+)?,?") + .xpr("([^,;]+)?,?") + .any() + .compile(); + + private static final Pattern PATTERN_HANDSHAKE = new PatternBuilder() + .num("##,imei:(d+),A") + .compile(); @Override protected Object decode( @@ -71,9 +78,9 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder { if (sentence.contains("##")) { if (channel != null) { channel.write("LOAD", remoteAddress); - Matcher handshakeMatcher = PATTERN_HANDSHAKE.matcher(sentence); - if (handshakeMatcher.matches()) { - identify(handshakeMatcher.group(1), channel); + Parser handshakeParser = new Parser(PATTERN_HANDSHAKE, sentence); + if (handshakeParser.matches()) { + identify(handshakeParser.next(), channel); } } return null; @@ -87,120 +94,60 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder { return null; } - // Parse message - Matcher parser = PATTERN.matcher(sentence); + Parser parser = new Parser(PATTERN, sentence); if (!parser.matches()) { return null; } - // Create new position Position position = new Position(); position.setProtocol(getProtocolName()); - Integer index = 1; - // Get device by IMEI - String imei = parser.group(index++); + String imei = parser.next(); if (!identify(imei, channel, remoteAddress)) { return null; } position.setDeviceId(getDeviceId()); - // Alarm message - String alarm = parser.group(index++); + String alarm = parser.next(); position.set(Event.KEY_ALARM, alarm); if (channel != null && alarm.equals("help me")) { channel.write("**,imei:" + imei + ",E;", remoteAddress); } - // Date - Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - time.clear(); - time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++))); - time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1); - time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++))); - - int localHours = Integer.parseInt(parser.group(index++)); - int localMinutes = Integer.parseInt(parser.group(index++)); - - String utcHours = parser.group(index++); - String utcMinutes = parser.group(index++); - - // Time - time.set(Calendar.HOUR_OF_DAY, localHours); - time.set(Calendar.MINUTE, localMinutes); - String seconds = parser.group(index++); - if (seconds != null) { - time.set(Calendar.SECOND, Integer.parseInt(seconds)); - } - String milliseconds = parser.group(index++); - if (milliseconds != null) { - time.set(Calendar.MILLISECOND, Integer.parseInt(milliseconds)); - } + DateBuilder dateBuilder = new DateBuilder() + .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + int localHours = parser.nextInt(); + int localMinutes = parser.nextInt(); + + int utcHours = parser.nextInt(); + int utcMinutes = parser.nextInt(); + + dateBuilder.setTime(localHours, localMinutes, parser.nextInt(), parser.nextInt()); // Timezone calculation - if (utcHours != null && utcMinutes != null) { - int deltaMinutes = (localHours - Integer.parseInt(utcHours)) * 60; - deltaMinutes += localMinutes - Integer.parseInt(utcMinutes); + if (utcHours != 0 && utcMinutes != 0) { + int deltaMinutes = (localHours - utcHours) * 60; + deltaMinutes += localMinutes - utcMinutes; if (deltaMinutes <= -12 * 60) { deltaMinutes += 24 * 60; } else if (deltaMinutes > 12 * 60) { deltaMinutes -= 24 * 60; } - time.add(Calendar.MINUTE, -deltaMinutes); + dateBuilder.addMinute(-deltaMinutes); } - position.setTime(time.getTime()); - - // Validity - position.setValid(parser.group(index++).compareTo("A") == 0); + position.setTime(dateBuilder.getDate()); - // Latitude - String hemisphere = parser.group(index++); - Double latitude = Double.parseDouble(parser.group(index++)); - latitude += Double.parseDouble(parser.group(index++)) / 60; - if (parser.group(index) != null) { - hemisphere = parser.group(index); - } - index++; - if (hemisphere.compareTo("S") == 0) { - latitude = -latitude; - } - position.setLatitude(latitude); - - // Longitude - hemisphere = parser.group(index++); - Double longitude = Double.parseDouble(parser.group(index++)); - longitude += Double.parseDouble(parser.group(index++)) / 60; - if (parser.group(index) != null) { - hemisphere = parser.group(index); - } - index++; - if (hemisphere != null && hemisphere.compareTo("W") == 0) { - longitude = -longitude; - } - position.setLongitude(longitude); - - // Speed - String speed = parser.group(index++); - if (speed != null) { - position.setSpeed(Double.parseDouble(speed)); - } - - // Course - String course = parser.group(index++); - if (course != null) { - position.setCourse(Double.parseDouble(course)); - } - - // Altitude - String altitude = parser.group(index++); - if (altitude != null) { - position.setAltitude(Double.parseDouble(altitude)); - } + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_HEM)); + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextDouble()); + position.setAltitude(parser.nextDouble()); - // Additional data for (int i = 1; i <= 5; i++) { - position.set(Event.PREFIX_IO + i, parser.group(index++)); + position.set(Event.PREFIX_IO + i, parser.next()); } return position; -- cgit v1.2.3