aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2018-06-09 22:22:01 +1200
committerAnton Tananaev <anton.tananaev@gmail.com>2018-06-09 22:22:01 +1200
commitf56db9b1d895c027d983696db7daed900ca881ab (patch)
tree0234672ddeb9187f60d802f7eae6823ed7a46915
parentba67624e3c4d18f313aa0167d7276a58bdbac445 (diff)
downloadtraccar-server-f56db9b1d895c027d983696db7daed900ca881ab.tar.gz
traccar-server-f56db9b1d895c027d983696db7daed900ca881ab.tar.bz2
traccar-server-f56db9b1d895c027d983696db7daed900ca881ab.zip
Implement eSeal CT-C protocol
-rw-r--r--setup/default.xml1
-rw-r--r--src/org/traccar/model/Position.java2
-rw-r--r--src/org/traccar/protocol/EsealProtocol.java47
-rw-r--r--src/org/traccar/protocol/EsealProtocolDecoder.java154
-rw-r--r--test/org/traccar/protocol/EsealProtocolDecoderTest.java33
5 files changed, 237 insertions, 0 deletions
diff --git a/setup/default.xml b/setup/default.xml
index c427217f7..15d169f63 100644
--- a/setup/default.xml
+++ b/setup/default.xml
@@ -244,5 +244,6 @@
<entry key='sabertek.port'>5166</entry>
<entry key='retranslator.port'>5167</entry>
<entry key='svias.port'>5168</entry>
+ <entry key='eseal.port'>5169</entry>
</properties>
diff --git a/src/org/traccar/model/Position.java b/src/org/traccar/model/Position.java
index b0fe7a79b..4b327cbd2 100644
--- a/src/org/traccar/model/Position.java
+++ b/src/org/traccar/model/Position.java
@@ -112,6 +112,8 @@ public class Position extends Message {
public static final String ALARM_POWER_OFF = "powerOff";
public static final String ALARM_POWER_ON = "powerOn";
public static final String ALARM_DOOR = "door";
+ public static final String ALARM_LOCK = "lock";
+ public static final String ALARM_UNLOCK = "unlock";
public static final String ALARM_GEOFENCE = "geofence";
public static final String ALARM_GEOFENCE_ENTER = "geofenceEnter";
public static final String ALARM_GEOFENCE_EXIT = "geofenceExit";
diff --git a/src/org/traccar/protocol/EsealProtocol.java b/src/org/traccar/protocol/EsealProtocol.java
new file mode 100644
index 000000000..534e3d0c4
--- /dev/null
+++ b/src/org/traccar/protocol/EsealProtocol.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.frame.LineBasedFrameDecoder;
+import org.jboss.netty.handler.codec.string.StringDecoder;
+import org.jboss.netty.handler.codec.string.StringEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.TrackerServer;
+
+import java.util.List;
+
+public class EsealProtocol extends BaseProtocol {
+
+ public EsealProtocol() {
+ super("eseal");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ServerBootstrap(), getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
+ pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
+ pipeline.addLast("objectDecoder", new EsealProtocolDecoder(EsealProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/EsealProtocolDecoder.java b/src/org/traccar/protocol/EsealProtocolDecoder.java
new file mode 100644
index 000000000..67b45b33f
--- /dev/null
+++ b/src/org/traccar/protocol/EsealProtocolDecoder.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.Context;
+import org.traccar.DeviceSession;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+public class EsealProtocolDecoder extends BaseProtocolDecoder {
+
+ private String config;
+
+ public EsealProtocolDecoder(EsealProtocol protocol) {
+ super(protocol);
+ config = Context.getConfig().getString(getProtocolName() + ".config");
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("##S,")
+ .expression("[^,]+,") // device type
+ .number("(d+),") // device id
+ .number("d+,") // customer id
+ .expression("[^,]+,") // firmware version
+ .expression("([^,]+),") // type
+ .number("(d+),") // index
+ .number("(dddd)-(dd)-(dd),") // date
+ .number("(dd):(dd):(dd),") // time
+ .number("d+,") // interval
+ .expression("([AV]),") // validity
+ .number("(d+.d+)([NS]) ") // latitude
+ .number("(d+.d+)([EW]),") // longitude
+ .number("(d+),") // course
+ .number("(d+),") // speed
+ .expression("([^,]+),") // door
+ .number("(d+.d+),") // acceleration
+ .expression("([^,]+),") // nfc
+ .number("(d+.d+),") // battery
+ .number("(-?d+),") // rssi
+ .text("E##")
+ .compile();
+
+ private void sendResponse(Channel channel, String prefix, String type, String payload) {
+ if (channel != null) {
+ channel.write(prefix + type + "," + payload + ",E##\r\n");
+ }
+ }
+
+ private String decodeAlarm(String type) {
+ switch (type) {
+ case "Event-Door":
+ return Position.ALARM_DOOR;
+ case "Event-Shock":
+ return Position.ALARM_SHOCK;
+ case "Event-Drop":
+ return Position.ALARM_FALL_DOWN;
+ case "Event-Lock":
+ return Position.ALARM_LOCK;
+ case "Event-RC-Unlock":
+ return Position.ALARM_UNLOCK;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ String sentence = (String) msg;
+ Parser parser = new Parser(PATTERN, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ String type = parser.next();
+ String prefix = sentence.substring(0, sentence.indexOf(type));
+ int index = parser.nextInt();
+
+ position.set(Position.KEY_INDEX, index);
+ position.set(Position.KEY_ALARM, decodeAlarm(type));
+
+ switch (type) {
+ case "Startup":
+ sendResponse(channel, prefix, type + " ACK", index + "," + config);
+ break;
+ case "Normal":
+ case "Termination":
+ case "Event-Door":
+ case "Event-Shock":
+ case "Event-Drop":
+ case "Event-Lock":
+ case "Event-RC-Unlock":
+ sendResponse(channel, prefix, type + " ACK", String.valueOf(index));
+ break;
+ default:
+ break;
+ }
+
+ position.setTime(parser.nextDateTime());
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setCourse(parser.nextInt());
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt()));
+
+ switch (parser.next()) {
+ case "Open":
+ position.set(Position.KEY_DOOR, true);
+ break;
+ case "Close":
+ position.set(Position.KEY_DOOR, false);
+ break;
+ default:
+ break;
+ }
+
+ position.set(Position.KEY_ACCELERATION, parser.nextDouble());
+ position.set("nfc", parser.next());
+ position.set(Position.KEY_BATTERY, parser.nextDouble());
+ position.set(Position.KEY_RSSI, parser.nextInt());
+
+ return position;
+ }
+
+}
diff --git a/test/org/traccar/protocol/EsealProtocolDecoderTest.java b/test/org/traccar/protocol/EsealProtocolDecoderTest.java
new file mode 100644
index 000000000..c14652dd1
--- /dev/null
+++ b/test/org/traccar/protocol/EsealProtocolDecoderTest.java
@@ -0,0 +1,33 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class EsealProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ EsealProtocolDecoder decoder = new EsealProtocolDecoder(new EsealProtocol());
+
+ verifyPosition(decoder, text(
+ "##S,eSeal,1000821,256,3.0.6,Normal,34,2017-08-31,08:14:40,15,A,25.708828N 100.372870W,10,0,Close,0.71,0:0:3:0,3.8,-73,E##"));
+
+ verifyPosition(decoder, text(
+ "##S,eSeal,1000821,256,3.0.6,Startup,1,2017-08-31,02:01:19,3,V,0.000000N 0.000000E,0,0,Close,3.25,0:0:5:0,3.8,-93,E##"));
+
+ verifyNull(decoder, text(
+ "##S,eSeal,1000821,256,3.0.6,Startup OK,1,180,30,30,16,1,E##"));
+
+ verifyNull(decoder, text(
+ "##S,eSeal,1000821,256,3.0.6,Startup OK,1,180,30,30,16,1,E##"));
+
+ verifyPosition(decoder, text(
+ "##S,eSeal,1000898,256,3.0.6,Normal,6,2017-09-06,23:48:39,3,V,0.000000N 0.000000E,0,0,Close,1.0,0:0:3:0,4.0,-81,E##"));
+
+ verifyNull(decoder, text(
+ "##S,eSeal,1000898,256,3.0.6,RC-NFC DEL ACK,,E##"));
+
+ }
+
+}