aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2015-10-30 18:50:43 +1300
committerAnton Tananaev <anton.tananaev@gmail.com>2015-10-30 18:50:43 +1300
commitc4dc8997bd1fb1178d85a4d70d630782d53c1414 (patch)
treebde0184bd297973be7a06b66a6c0bc4ec7911b3b
parentea342be81728290bb529bcecfd9a68874c8b46a6 (diff)
downloadtraccar-server-c4dc8997bd1fb1178d85a4d70d630782d53c1414.tar.gz
traccar-server-c4dc8997bd1fb1178d85a4d70d630782d53c1414.tar.bz2
traccar-server-c4dc8997bd1fb1178d85a4d70d630782d53c1414.zip
Implement GPS watch protocol
-rw-r--r--debug.xml1
-rw-r--r--src/org/traccar/protocol/Tk102ProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/WatchProtocol.java47
-rw-r--r--src/org/traccar/protocol/WatchProtocolDecoder.java131
-rw-r--r--test/org/traccar/protocol/WatchProtocolDecoderTest.java34
5 files changed, 214 insertions, 1 deletions
diff --git a/debug.xml b/debug.xml
index 43070f9ec..a5951ddd4 100644
--- a/debug.xml
+++ b/debug.xml
@@ -334,5 +334,6 @@
<entry key='flextrack.port'>5090</entry>
<entry key='blackkite.port'>5091</entry>
<entry key='adm.port'>5092</entry>
+ <entry key='watch.port'>5093</entry>
</properties>
diff --git a/src/org/traccar/protocol/Tk102ProtocolDecoder.java b/src/org/traccar/protocol/Tk102ProtocolDecoder.java
index e9fb86cc2..386f465a5 100644
--- a/src/org/traccar/protocol/Tk102ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Tk102ProtocolDecoder.java
@@ -41,7 +41,7 @@ public class Tk102ProtocolDecoder extends BaseProtocolDecoder {
.expression("([AV])") // validity
.number("(dd)(dd.dddd)([NS])") // latitude
.number("(ddd)(dd.dddd)([EW])") // longitude
- .number("(ddd.ddd)") // Speed
+ .number("(ddd.ddd)") // speed
.number("(dd)(dd)(dd)") // date (ddmmyy)
.number("d+")
.any()
diff --git a/src/org/traccar/protocol/WatchProtocol.java b/src/org/traccar/protocol/WatchProtocol.java
new file mode 100644
index 000000000..b5270f5c1
--- /dev/null
+++ b/src/org/traccar/protocol/WatchProtocol.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.handler.codec.string.StringDecoder;
+import org.jboss.netty.handler.codec.string.StringEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.CharacterDelimiterFrameDecoder;
+import org.traccar.TrackerServer;
+
+import java.util.List;
+
+public class WatchProtocol extends BaseProtocol {
+
+ public WatchProtocol() {
+ super("tk102");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ServerBootstrap(), this.getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, ']'));
+ pipeline.addLast("stringDecoder", new StringDecoder());
+ pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("objectDecoder", new WatchProtocolDecoder(WatchProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/WatchProtocolDecoder.java b/src/org/traccar/protocol/WatchProtocolDecoder.java
new file mode 100644
index 000000000..7f64f1efa
--- /dev/null
+++ b/src/org/traccar/protocol/WatchProtocolDecoder.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.helper.*;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+public class WatchProtocolDecoder extends BaseProtocolDecoder {
+
+ public WatchProtocolDecoder(WatchProtocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("[")
+ .expression("(..)").text("*") // manufacturer
+ .number("(d+)").text("*") // equipment id
+ .number("xxxx").text("*") // length
+ .expression("([^,]+)") // type
+ .expression("(.*)") // content
+ .compile();
+
+ private static final Pattern PATTERN_POSITION = new PatternBuilder()
+ .text(",")
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .number("(dd)(dd)(dd),") // time
+ .expression("([AV]),") // validity
+ .number("(d+.d+),") // latitude
+ .expression("([NS]),")
+ .number("(d+.d+),") // longitude
+ .expression("([EW]),")
+ .number("(d+.d+),") // speed
+ .number("(d+.d+),") // course
+ .number("(d+),") // altitude
+ .number("(d+),") // satellites
+ .number("(d+),") // gsm
+ .number("(d+),") // battery
+ .number("(d+),") // steps
+ .number("d+,") // tumbles
+ .any()
+ .compile();
+
+ private void sendResponse(Channel channel, String manufacturer, String id, String content) {
+ if (channel != null) {
+ channel.write(
+ String.format("[%s*%s*%04x*%s]", manufacturer, id, content.length(), content));
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ Parser parser = new Parser(PATTERN, (String) msg);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ String manufacturer = parser.next();
+ String id = parser.next();
+ if (!identify(id, channel)) {
+ return null;
+ }
+
+ String type = parser.next();
+ String content = parser.next();
+
+ if (type.equals("LK")) {
+
+ sendResponse(channel, manufacturer, id, "LK");
+
+ } else if (type.equals("UD") || type.equals("UD2") || type.equals("AL")) {
+
+ if (type.equals("AL")) {
+ sendResponse(channel, manufacturer, id, "AL");
+ }
+
+ parser = new Parser(PATTERN_POSITION, content);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(getDeviceId());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
+ position.setAltitude(parser.nextDouble());
+
+ position.set(Event.KEY_SATELLITES, parser.nextInt());
+ position.set(Event.KEY_GSM, parser.nextInt());
+ position.set(Event.KEY_BATTERY, parser.nextInt());
+
+ position.set("steps", parser.nextInt());
+
+ return position;
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/test/org/traccar/protocol/WatchProtocolDecoderTest.java b/test/org/traccar/protocol/WatchProtocolDecoderTest.java
new file mode 100644
index 000000000..712b38f5b
--- /dev/null
+++ b/test/org/traccar/protocol/WatchProtocolDecoderTest.java
@@ -0,0 +1,34 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolDecoderTest;
+
+public class WatchProtocolDecoderTest extends ProtocolDecoderTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ WatchProtocolDecoder decoder = new WatchProtocolDecoder(new WatchProtocol());
+
+ verifyNothing(decoder, text(
+ "[SG*8800000015*0002*LK"));
+
+ verifyNothing(decoder, text(
+ "[3G*4700186508*000B*LK,0,10,100"));
+
+ verifyPosition(decoder, text(
+ "[SG*8800000015*0087*UD,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0000,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141"),
+ position("2014-04-22 13:46:52.000", true, 22.57171, 113.86140));
+
+ verifyPosition(decoder, text(
+ "[SG*8800000015*0087*UD,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0000,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141"));
+
+ verifyPosition(decoder, text(
+ "[SG*8800000015*0088*UD2,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0000,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141"));
+
+ verifyPosition(decoder, text(
+ "[SG*8800000015*0087*AL,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0001,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141"));
+
+ }
+
+}