aboutsummaryrefslogtreecommitdiff
path: root/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2019-02-10 13:49:44 -0800
committerAnton Tananaev <anton.tananaev@gmail.com>2019-02-10 13:49:44 -0800
commit3d2a3ee8ccf6f0989a149eec74b3d69d42963756 (patch)
treec7cc153246b818c2b672482a7f5cb988ee29e311 /src/org/traccar/protocol/TeltonikaProtocolDecoder.java
parenta50b9a890aaf5a1388f84449cc2978d55328e874 (diff)
downloadtraccar-server-3d2a3ee8ccf6f0989a149eec74b3d69d42963756.tar.gz
traccar-server-3d2a3ee8ccf6f0989a149eec74b3d69d42963756.tar.bz2
traccar-server-3d2a3ee8ccf6f0989a149eec74b3d69d42963756.zip
Support camera for Teltonika
Diffstat (limited to 'src/org/traccar/protocol/TeltonikaProtocolDecoder.java')
-rw-r--r--src/org/traccar/protocol/TeltonikaProtocolDecoder.java85
1 files changed, 76 insertions, 9 deletions
diff --git a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
index f69059104..0e1fd6280 100644
--- a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
+++ b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2019 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.
@@ -25,6 +25,7 @@ import org.traccar.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
+import org.traccar.helper.Checksum;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
@@ -33,13 +34,18 @@ import org.traccar.model.Position;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Date;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
+ private static final int IMAGE_PACKET_MAX = 2048;
+
private boolean connectionless;
private boolean extended;
+ private Map<Long, ByteBuf> photos = new HashMap<>();
public void setExtended(boolean extended) {
this.extended = extended;
@@ -51,7 +57,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
this.extended = Context.getConfig().getBoolean(getProtocolName() + ".extended");
}
- private DeviceSession parseIdentification(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
+ private void parseIdentification(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
int length = buf.readUnsignedShort();
String imei = buf.toString(buf.readerIndex(), length, StandardCharsets.US_ASCII);
@@ -66,7 +72,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
}
channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
}
- return deviceSession;
}
public static final int CODEC_GH3000 = 0x07;
@@ -75,14 +80,74 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
public static final int CODEC_12 = 0x0C;
public static final int CODEC_16 = 0x10;
- private void decodeSerial(Position position, ByteBuf buf) {
+ private void sendImageRequest(Channel channel, SocketAddress remoteAddress, long id, int offset, int size) {
+ if (channel != null) {
+ ByteBuf response = Unpooled.buffer();
+ response.writeInt(0);
+ response.writeShort(0);
+ response.writeShort(19); // length
+ response.writeByte(CODEC_12);
+ response.writeByte(1); // nod
+ response.writeByte(0x0D); // camera
+ response.writeInt(11); // payload length
+ response.writeByte(2); // command
+ response.writeInt((int) id);
+ response.writeInt(offset);
+ response.writeShort(size);
+ response.writeByte(1); // nod
+ response.writeShort(0);
+ response.writeShort(Checksum.crc16(
+ Checksum.CRC16_IBM, response.nioBuffer(8, response.readableBytes() - 8)));
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
+ }
+ }
+
+ private void decodeSerial(Channel channel, SocketAddress remoteAddress, Position position, ByteBuf buf) {
getLastLocation(position, null);
- position.set(Position.KEY_TYPE, buf.readUnsignedByte());
+ int type = buf.readUnsignedByte();
+ if (type == 0x0D) {
+
+ buf.readInt(); // length
+ int subtype = buf.readUnsignedByte();
+ if (subtype == 0x01) {
+
+ long photoId = buf.readUnsignedInt();
+ ByteBuf photo = Unpooled.buffer(buf.readInt());
+ photos.put(photoId, photo);
+ sendImageRequest(
+ channel, remoteAddress, photoId,
+ 0, Math.min(IMAGE_PACKET_MAX, photo.capacity()));
+
+ } else if (subtype == 0x02) {
+
+ long photoId = buf.readUnsignedInt();
+ buf.readInt(); // offset
+ ByteBuf photo = photos.get(photoId);
+ photo.writeBytes(buf, buf.readUnsignedShort());
+ if (photo.writableBytes() > 0) {
+ sendImageRequest(
+ channel, remoteAddress, photoId,
+ photo.writerIndex(), Math.min(IMAGE_PACKET_MAX, photo.writableBytes()));
+ } else {
+ String uniqueId = Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId();
+ photos.remove(photoId);
+ try {
+ position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg"));
+ } finally {
+ photo.release();
+ }
+ }
+
+ }
- position.set(Position.KEY_RESULT, buf.readSlice(buf.readInt()).toString(StandardCharsets.US_ASCII));
+ } else {
+ position.set(Position.KEY_TYPE, type);
+ position.set(Position.KEY_RESULT, buf.readSlice(buf.readInt()).toString(StandardCharsets.US_ASCII));
+
+ }
}
private long readValue(ByteBuf buf, int length, boolean signed) {
@@ -462,12 +527,14 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
position.setValid(true);
if (codec == CODEC_12) {
- decodeSerial(position, buf);
+ decodeSerial(channel, remoteAddress, position, buf);
} else {
decodeLocation(position, buf, codec);
}
- positions.add(position);
+ if (!position.getOutdated() || !position.getAttributes().isEmpty()) {
+ positions.add(position);
+ }
}
if (channel != null) {
@@ -486,7 +553,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
}
}
- return positions;
+ return positions.isEmpty() ? null : positions;
}
@Override