aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVijay Kumar B <vijaykumar@zilogic.com>2015-09-28 16:50:26 +0530
committerVijay Kumar B <vijaykumar@zilogic.com>2015-09-28 16:52:22 +0530
commita4a776911eb2a1a88ccd05bbd418313342cfc208 (patch)
tree96046514790019740bf56886bd0e1bfaea2eff5b
parent2a690606569f042b845da1f61b308698645ad3fc (diff)
downloadtraccar-server-a4a776911eb2a1a88ccd05bbd418313342cfc208.tar.gz
traccar-server-a4a776911eb2a1a88ccd05bbd418313342cfc208.tar.bz2
traccar-server-a4a776911eb2a1a88ccd05bbd418313342cfc208.zip
Add support for BlackKite protocol.
BlackKite is closely based on the Galileo protocol. We derive code from the Galileo protocol and make changes as required to meet BlackKite protocol specifications.
-rw-r--r--debug.xml1
-rw-r--r--setup/unix/traccar.xml1
-rw-r--r--setup/windows/traccar.xml1
-rw-r--r--src/org/traccar/model/Event.java2
-rw-r--r--src/org/traccar/protocol/BlackKiteProtocol.java48
-rw-r--r--src/org/traccar/protocol/BlackKiteProtocolDecoder.java232
-rw-r--r--test/org/traccar/protocol/BlackKiteProtocolDecoderTest.java25
-rw-r--r--tools/opengts.xml1
8 files changed, 310 insertions, 1 deletions
diff --git a/debug.xml b/debug.xml
index d3c01616a..29b859c9c 100644
--- a/debug.xml
+++ b/debug.xml
@@ -338,5 +338,6 @@
<entry key='cityeasy.port'>5088</entry>
<entry key='aquila.port'>5089</entry>
<entry key='flextrack.port'>5090</entry>
+ <entry key='blackkite.port'>5091</entry>
</properties>
diff --git a/setup/unix/traccar.xml b/setup/unix/traccar.xml
index 70270b7d1..06dd293ea 100644
--- a/setup/unix/traccar.xml
+++ b/setup/unix/traccar.xml
@@ -317,5 +317,6 @@
<entry key='castel.port'>5086</entry>
<entry key='mxt.port'>5087</entry>
<entry key='cityeasy.port'>5088</entry>
+ <entry key='blackkite.port'>5091</entry>
</properties>
diff --git a/setup/windows/traccar.xml b/setup/windows/traccar.xml
index bf0dc3efa..ce3f4ebdc 100644
--- a/setup/windows/traccar.xml
+++ b/setup/windows/traccar.xml
@@ -317,5 +317,6 @@
<entry key='castel.port'>5086</entry>
<entry key='mxt.port'>5087</entry>
<entry key='cityeasy.port'>5088</entry>
+ <entry key='blackkite.port'>5091</entry>
</properties>
diff --git a/src/org/traccar/model/Event.java b/src/org/traccar/model/Event.java
index cadca767b..cfa51e82e 100644
--- a/src/org/traccar/model/Event.java
+++ b/src/org/traccar/model/Event.java
@@ -81,9 +81,9 @@ public abstract class Event {
public static final String KEY_DISTANCE = "distance";
public static final String KEY_DOOR = "door";
public static final String KEY_RPM = "rpm";
-
public static final String KEY_OBD_SPEED = "speed";
public static final String KEY_OBD_ODOMETER = "odometer";
+ public static final String KEY_VBATT = "vehicle-battery";
// Starts with 1 not 0
public static final String PREFIX_TEMP = "temp";
diff --git a/src/org/traccar/protocol/BlackKiteProtocol.java b/src/org/traccar/protocol/BlackKiteProtocol.java
new file mode 100644
index 000000000..0bdafd750
--- /dev/null
+++ b/src/org/traccar/protocol/BlackKiteProtocol.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 Vijay Kumar (vijaykumar@zilogic.com)
+ *
+ * Based on GalileoProtocol.java
+ * 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.traccar.BaseProtocol;
+import org.traccar.TrackerServer;
+
+import java.nio.ByteOrder;
+import java.util.List;
+
+public class BlackKiteProtocol extends BaseProtocol {
+
+ public BlackKiteProtocol() {
+ super("blackkite");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ TrackerServer server = new TrackerServer(new ServerBootstrap(), this.getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new GalileoFrameDecoder());
+ pipeline.addLast("objectDecoder", new BlackKiteProtocolDecoder(BlackKiteProtocol.this));
+ }
+ };
+ server.setEndianness(ByteOrder.LITTLE_ENDIAN);
+ serverList.add(server);
+ }
+
+}
diff --git a/src/org/traccar/protocol/BlackKiteProtocolDecoder.java b/src/org/traccar/protocol/BlackKiteProtocolDecoder.java
new file mode 100644
index 000000000..4f63dbafa
--- /dev/null
+++ b/src/org/traccar/protocol/BlackKiteProtocolDecoder.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2015 Vijay Kumar (vijaykumar@zilogic.com)
+ *
+ * Based on GalileoProtocolDecoder.java
+ * Copyright 2013 - 2014 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 java.net.SocketAddress;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.helper.Log;
+import org.traccar.helper.BitUtil;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+
+class DecodeError extends Exception {
+ public DecodeError(String message) {
+ super(message);
+ }
+}
+
+
+public class BlackKiteProtocolDecoder extends BaseProtocolDecoder {
+
+ public BlackKiteProtocolDecoder(BlackKiteProtocol protocol) {
+ super(protocol);
+ }
+
+ private static final int TAG_IMEI = 0x03;
+ private static final int TAG_DATE = 0x20;
+ private static final int TAG_COORDINATES = 0x30;
+ private static final int TAG_SPEED_COURSE = 0x33;
+ private static final int TAG_ALTITUDE = 0x34;
+ private static final int TAG_STATUS = 0x40;
+ private static final int TAG_DIGITAL_OUTPUTS = 0x45;
+ private static final int TAG_DIGITAL_INPUTS = 0x46;
+ private static final int TAG_INPUT_VOLTAGE1 = 0x50;
+ private static final int TAG_INPUT_VOLTAGE2 = 0x51;
+ private static final int TAG_INPUT_VOLTAGE3 = 0x52;
+ private static final int TAG_INPUT_VOLTAGE4 = 0x53;
+ private static final int TAG_XT1 = 0x60;
+ private static final int TAG_XT2 = 0x61;
+ private static final int TAG_XT3 = 0x62;
+
+ private static final Map<Integer, Integer> tagLengthMap = new HashMap<>();
+
+ static {
+ tagLengthMap.put(TAG_IMEI, 15);
+ tagLengthMap.put(TAG_DATE, 4);
+ tagLengthMap.put(TAG_COORDINATES, 9);
+ tagLengthMap.put(TAG_SPEED_COURSE, 4);
+ tagLengthMap.put(TAG_ALTITUDE, 2);
+ tagLengthMap.put(TAG_STATUS, 2);
+ tagLengthMap.put(TAG_DIGITAL_INPUTS, 2);
+ tagLengthMap.put(TAG_DIGITAL_OUTPUTS, 2);
+ tagLengthMap.put(TAG_INPUT_VOLTAGE1, 2);
+ tagLengthMap.put(TAG_INPUT_VOLTAGE2, 2);
+ tagLengthMap.put(TAG_INPUT_VOLTAGE3, 2);
+ tagLengthMap.put(TAG_INPUT_VOLTAGE4, 2);
+ tagLengthMap.put(TAG_XT1, 16);
+ tagLengthMap.put(TAG_XT2, 16);
+ tagLengthMap.put(TAG_XT3, 16);
+ }
+
+ private static int getTagLength(int tag) throws DecodeError {
+ Integer length = tagLengthMap.get(tag);
+ if (length == null)
+ throw new DecodeError(String.format("invalid tag '%d'", tag));
+
+ return length;
+ }
+
+ private void sendReply(Channel channel, int checksum) {
+ ChannelBuffer reply = ChannelBuffers.directBuffer(ByteOrder.LITTLE_ENDIAN, 3);
+ reply.writeByte(0x02);
+ reply.writeShort((short) checksum);
+ if (channel != null) {
+ channel.write(reply);
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg)
+ throws Exception {
+
+ ChannelBuffer buf = (ChannelBuffer) msg;
+
+ buf.readUnsignedByte(); // header
+ int length = (buf.readUnsignedShort() & 0x7fff) + 3;
+
+ List<Position> positions = new LinkedList<Position>();
+ Set<Integer> tags = new HashSet<Integer>();
+ boolean hasLocation = false;
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+
+ while (buf.readerIndex() < length) {
+
+ // Check if new message started
+ int tag = buf.readUnsignedByte();
+ if (tags.contains(tag)) {
+ if (hasLocation && position.getFixTime() != null) {
+ positions.add(position);
+ }
+ tags.clear();
+ hasLocation = false;
+ position = new Position();
+ }
+ tags.add(tag);
+
+ switch (tag) {
+
+ case TAG_IMEI:
+ String imei = buf.toString(buf.readerIndex(), 15, Charset.defaultCharset());
+ buf.skipBytes(imei.length());
+ identify(imei, channel);
+ break;
+
+ case TAG_DATE:
+ position.setTime(new Date(buf.readUnsignedInt() * 1000));
+ break;
+
+ case TAG_COORDINATES:
+ hasLocation = true;
+ position.setValid((buf.readUnsignedByte() & 0xf0) == 0x00);
+ position.setLatitude(buf.readInt() / 1000000.0);
+ position.setLongitude(buf.readInt() / 1000000.0);
+ break;
+
+ case TAG_SPEED_COURSE:
+ position.setSpeed(buf.readUnsignedShort() * 0.0539957);
+ position.setCourse(buf.readUnsignedShort() * 0.1);
+ break;
+
+ case TAG_ALTITUDE:
+ position.setAltitude(buf.readShort());
+ break;
+
+ case TAG_STATUS:
+ int status = buf.readUnsignedShort();
+ position.set(Event.KEY_IGNITION, BitUtil.check(status, 9));
+ position.set(Event.KEY_ALARM, BitUtil.check(status, 15));
+ position.set(Event.KEY_VBATT, BitUtil.check(status, 2));
+ break;
+
+ case TAG_DIGITAL_INPUTS:
+ int input = buf.readUnsignedShort();
+ for (int i = 0; i < 16; i++)
+ position.set(Event.PREFIX_IO + (i + 1), BitUtil.check(input, i));
+ break;
+
+ case TAG_DIGITAL_OUTPUTS:
+ int output = buf.readUnsignedShort();
+ for (int i = 0; i < 16; i++)
+ position.set(Event.PREFIX_IO + (i + 17), BitUtil.check(output, i));
+ break;
+
+ case TAG_INPUT_VOLTAGE1:
+ position.set(Event.PREFIX_ADC + 1, buf.readUnsignedShort() / 1000.0);
+ break;
+
+ case TAG_INPUT_VOLTAGE2:
+ position.set(Event.PREFIX_ADC + 2, buf.readUnsignedShort() / 1000.0);
+ break;
+
+ case TAG_INPUT_VOLTAGE3:
+ position.set(Event.PREFIX_ADC + 3, buf.readUnsignedShort() / 1000.0);
+ break;
+
+ case TAG_INPUT_VOLTAGE4:
+ position.set(Event.PREFIX_ADC + 4, buf.readUnsignedShort() / 1000.0);
+ break;
+
+ default:
+ try {
+ buf.skipBytes(getTagLength(tag));
+ } catch (DecodeError e) {
+ Log.warning("Error decoding packet: " + e.getMessage());
+ return null;
+ }
+ break;
+
+ }
+ }
+ if (hasLocation && position.getFixTime() != null) {
+ positions.add(position);
+ }
+
+ if (!hasDeviceId()) {
+ Log.warning("Unknown device");
+ return null;
+ }
+
+ sendReply(channel, buf.readUnsignedShort());
+
+ for (Position p : positions) {
+ p.setDeviceId(getDeviceId());
+ }
+
+ if (positions.isEmpty()) {
+ return null;
+ }
+ return positions;
+ }
+
+}
diff --git a/test/org/traccar/protocol/BlackKiteProtocolDecoderTest.java b/test/org/traccar/protocol/BlackKiteProtocolDecoderTest.java
new file mode 100644
index 000000000..3060bb3f8
--- /dev/null
+++ b/test/org/traccar/protocol/BlackKiteProtocolDecoderTest.java
@@ -0,0 +1,25 @@
+package org.traccar.protocol;
+
+import org.traccar.helper.TestIdentityManager;
+import java.nio.ByteOrder;
+import org.jboss.netty.buffer.ChannelBuffers;
+import static org.junit.Assert.assertNull;
+import org.junit.Test;
+import org.traccar.helper.ChannelBufferTools;
+import static org.traccar.helper.DecoderVerifier.verify;
+
+public class BlackKiteProtocolDecoderTest extends ProtocolDecoderTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ BlackKiteProtocolDecoder decoder = new BlackKiteProtocolDecoder(new BlackKiteProtocol());
+
+ assertNull(decoder.decode(null, null, ChannelBuffers.wrappedBuffer(ByteOrder.LITTLE_ENDIAN, ChannelBufferTools.convertHexString(
+ "01150003313131313131313131313131313131209836055605BA"))));
+
+ verify(decoder.decode(null, null, ChannelBuffers.wrappedBuffer(ByteOrder.LITTLE_ENDIAN, ChannelBufferTools.convertHexString(
+ "0136000331313131313131313131313131313120523905563000010000000100000033000000003400004000004500004600005000005100009F76"))));
+ }
+
+}
diff --git a/tools/opengts.xml b/tools/opengts.xml
index b1bfa197b..a1144d593 100644
--- a/tools/opengts.xml
+++ b/tools/opengts.xml
@@ -124,5 +124,6 @@
<entry key='tytan.port'>5084</entry>
<entry key='avl301.port'>5085</entry>
<entry key='castel.port'>5086</entry>
+ <entry key='blackkite.port'>5091</entry>
</properties>