diff options
Diffstat (limited to 'src/org/traccar/protocol/TeltonikaProtocolDecoder.java')
-rw-r--r-- | src/org/traccar/protocol/TeltonikaProtocolDecoder.java | 597 |
1 files changed, 0 insertions, 597 deletions
diff --git a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java deleted file mode 100644 index 974d2c106..000000000 --- a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ /dev/null @@ -1,597 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -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; -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; - } - - public TeltonikaProtocolDecoder(Protocol protocol, boolean connectionless) { - super(protocol); - this.connectionless = connectionless; - this.extended = Context.getConfig().getBoolean(getProtocolName() + ".extended"); - } - - private void parseIdentification(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - int length = buf.readUnsignedShort(); - String imei = buf.toString(buf.readerIndex(), length, StandardCharsets.US_ASCII); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - - if (channel != null) { - ByteBuf response = Unpooled.buffer(1); - if (deviceSession != null) { - response.writeByte(1); - } else { - response.writeByte(0); - } - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - public static final int CODEC_GH3000 = 0x07; - public static final int CODEC_8 = 0x08; - public static final int CODEC_8_EXT = 0x8E; - public static final int CODEC_12 = 0x0C; - public static final int CODEC_16 = 0x10; - - 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() - 10))); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - private void decodeSerial(Channel channel, SocketAddress remoteAddress, Position position, ByteBuf buf) { - - getLastLocation(position, null); - - 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(); - } - } - - } - - } 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) { - switch (length) { - case 1: - return signed ? buf.readByte() : buf.readUnsignedByte(); - case 2: - return signed ? buf.readShort() : buf.readUnsignedShort(); - case 4: - return signed ? buf.readInt() : buf.readUnsignedInt(); - default: - return buf.readLong(); - } - } - - private void decodeOtherParameter(Position position, int id, ByteBuf buf, int length) { - switch (id) { - case 1: - case 2: - case 3: - case 4: - position.set("di" + id, readValue(buf, length, false)); - break; - case 9: - position.set(Position.PREFIX_ADC + 1, readValue(buf, length, false)); - break; - case 17: - position.set("axisX", readValue(buf, length, true)); - break; - case 18: - position.set("axisY", readValue(buf, length, true)); - break; - case 19: - position.set("axisZ", readValue(buf, length, true)); - break; - case 21: - position.set(Position.KEY_RSSI, readValue(buf, length, false)); - break; - case 25: - case 26: - case 27: - case 28: - position.set(Position.PREFIX_TEMP + (id - 24), readValue(buf, length, true) * 0.1); - break; - case 66: - position.set(Position.KEY_POWER, readValue(buf, length, false) * 0.001); - break; - case 67: - position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001); - break; - case 69: - position.set("gpsStatus", readValue(buf, length, false)); - break; - case 72: - case 73: - case 74: - position.set(Position.PREFIX_TEMP + (id - 71), readValue(buf, length, true) * 0.1); - break; - case 78: - long driverUniqueId = readValue(buf, length, false); - if (driverUniqueId != 0) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", driverUniqueId)); - } - break; - case 80: - position.set("workMode", readValue(buf, length, false)); - break; - case 129: - case 130: - case 131: - case 132: - case 133: - case 134: - String driver = id == 129 || id == 132 ? "" : position.getString("driver1"); - position.set("driver" + (id >= 132 ? 2 : 1), - driver + buf.readSlice(length).toString(StandardCharsets.US_ASCII).trim()); - break; - case 179: - position.set(Position.PREFIX_OUT + 1, readValue(buf, length, false) == 1); - break; - case 180: - position.set(Position.PREFIX_OUT + 2, readValue(buf, length, false) == 1); - break; - case 181: - position.set(Position.KEY_PDOP, readValue(buf, length, false) * 0.1); - break; - case 182: - position.set(Position.KEY_HDOP, readValue(buf, length, false) * 0.1); - break; - case 236: - if (readValue(buf, length, false) == 1) { - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - } - break; - case 237: - position.set(Position.KEY_MOTION, readValue(buf, length, false) == 0); - break; - case 238: - switch ((int) readValue(buf, length, false)) { - case 1: - position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); - break; - case 2: - position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - break; - case 3: - position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); - break; - default: - break; - } - break; - case 239: - position.set(Position.KEY_IGNITION, readValue(buf, length, false) == 1); - break; - case 240: - position.set(Position.KEY_MOTION, readValue(buf, length, false) == 1); - break; - case 241: - position.set(Position.KEY_OPERATOR, readValue(buf, length, false)); - break; - default: - position.set(Position.PREFIX_IO + id, readValue(buf, length, false)); - break; - } - } - - private void decodeGh3000Parameter(Position position, int id, ByteBuf buf, int length) { - switch (id) { - case 1: - position.set(Position.KEY_BATTERY_LEVEL, readValue(buf, length, false)); - break; - case 2: - position.set("usbConnected", readValue(buf, length, false) == 1); - break; - case 5: - position.set("uptime", readValue(buf, length, false)); - break; - case 20: - position.set(Position.KEY_HDOP, readValue(buf, length, false) * 0.1); - break; - case 21: - position.set(Position.KEY_VDOP, readValue(buf, length, false) * 0.1); - break; - case 22: - position.set(Position.KEY_PDOP, readValue(buf, length, false) * 0.1); - break; - case 67: - position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001); - break; - case 221: - position.set("button", readValue(buf, length, false)); - break; - case 222: - if (readValue(buf, length, false) == 1) { - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - } - break; - case 240: - position.set(Position.KEY_MOTION, readValue(buf, length, false) == 1); - break; - case 244: - position.set(Position.KEY_ROAMING, readValue(buf, length, false) == 1); - break; - default: - position.set(Position.PREFIX_IO + id, readValue(buf, length, false)); - break; - } - } - - private void decodeParameter(Position position, int id, ByteBuf buf, int length, int codec) { - if (codec == CODEC_GH3000) { - decodeGh3000Parameter(position, id, buf, length); - } else { - decodeOtherParameter(position, id, buf, length); - } - } - - private void decodeNetwork(Position position) { - long cid = position.getLong(Position.PREFIX_IO + 205); - int lac = position.getInteger(Position.PREFIX_IO + 206); - if (cid != 0 && lac != 0) { - CellTower cellTower = CellTower.fromLacCid(lac, cid); - long operator = position.getInteger(Position.KEY_OPERATOR); - if (operator != 0) { - cellTower.setOperator(operator); - } - position.setNetwork(new Network(cellTower)); - } - } - - private int readExtByte(ByteBuf buf, int codec, int... codecs) { - boolean ext = false; - for (int c : codecs) { - if (codec == c) { - ext = true; - break; - } - } - if (ext) { - return buf.readUnsignedShort(); - } else { - return buf.readUnsignedByte(); - } - } - - private void decodeLocation(Position position, ByteBuf buf, int codec) { - - int globalMask = 0x0f; - - if (codec == CODEC_GH3000) { - - long time = buf.readUnsignedInt() & 0x3fffffff; - time += 1167609600; // 2007-01-01 00:00:00 - - globalMask = buf.readUnsignedByte(); - if (BitUtil.check(globalMask, 0)) { - - position.setTime(new Date(time * 1000)); - - int locationMask = buf.readUnsignedByte(); - - if (BitUtil.check(locationMask, 0)) { - position.setLatitude(buf.readFloat()); - position.setLongitude(buf.readFloat()); - } - - if (BitUtil.check(locationMask, 1)) { - position.setAltitude(buf.readUnsignedShort()); - } - - if (BitUtil.check(locationMask, 2)) { - position.setCourse(buf.readUnsignedByte() * 360.0 / 256); - } - - if (BitUtil.check(locationMask, 3)) { - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - } - - if (BitUtil.check(locationMask, 4)) { - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - } - - if (BitUtil.check(locationMask, 5)) { - CellTower cellTower = CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedShort()); - - if (BitUtil.check(locationMask, 6)) { - cellTower.setSignalStrength((int) buf.readUnsignedByte()); - } - - if (BitUtil.check(locationMask, 7)) { - cellTower.setOperator(buf.readUnsignedInt()); - } - - position.setNetwork(new Network(cellTower)); - - } else { - if (BitUtil.check(locationMask, 6)) { - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - } - if (BitUtil.check(locationMask, 7)) { - position.set(Position.KEY_OPERATOR, buf.readUnsignedInt()); - } - } - - } else { - - getLastLocation(position, new Date(time * 1000)); - - } - - } else { - - position.setTime(new Date(buf.readLong())); - - position.set("priority", buf.readUnsignedByte()); - - position.setLongitude(buf.readInt() / 10000000.0); - position.setLatitude(buf.readInt() / 10000000.0); - position.setAltitude(buf.readShort()); - position.setCourse(buf.readUnsignedShort()); - - int satellites = buf.readUnsignedByte(); - position.set(Position.KEY_SATELLITES, satellites); - - position.setValid(satellites != 0); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - - position.set(Position.KEY_EVENT, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16)); - if (codec == CODEC_16) { - buf.readUnsignedByte(); // generation type - } - - readExtByte(buf, codec, CODEC_8_EXT); // total IO data records - - } - - // Read 1 byte data - if (BitUtil.check(globalMask, 1)) { - int cnt = readExtByte(buf, codec, CODEC_8_EXT); - for (int j = 0; j < cnt; j++) { - decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 1, codec); - } - } - - // Read 2 byte data - if (BitUtil.check(globalMask, 2)) { - int cnt = readExtByte(buf, codec, CODEC_8_EXT); - for (int j = 0; j < cnt; j++) { - decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 2, codec); - } - } - - // Read 4 byte data - if (BitUtil.check(globalMask, 3)) { - int cnt = readExtByte(buf, codec, CODEC_8_EXT); - for (int j = 0; j < cnt; j++) { - decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 4, codec); - } - } - - // Read 8 byte data - if (codec == CODEC_8 || codec == CODEC_8_EXT || codec == CODEC_16) { - int cnt = readExtByte(buf, codec, CODEC_8_EXT); - for (int j = 0; j < cnt; j++) { - decodeOtherParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 8); - } - } - - // Read 16 byte data - if (extended) { - int cnt = readExtByte(buf, codec, CODEC_8_EXT); - for (int j = 0; j < cnt; j++) { - int id = readExtByte(buf, codec, CODEC_8_EXT, CODEC_16); - position.set(Position.PREFIX_IO + id, ByteBufUtil.hexDump(buf.readSlice(16))); - } - } - - // Read X byte data - if (codec == CODEC_8_EXT) { - int cnt = buf.readUnsignedShort(); - for (int j = 0; j < cnt; j++) { - int id = buf.readUnsignedShort(); - int length = buf.readUnsignedShort(); - if (id == 256) { - position.set(Position.KEY_VIN, buf.readSlice(length).toString(StandardCharsets.US_ASCII)); - } else { - position.set(Position.PREFIX_IO + id, ByteBufUtil.hexDump(buf.readSlice(length))); - } - } - } - - decodeNetwork(position); - - } - - private List<Position> parseData( - Channel channel, SocketAddress remoteAddress, ByteBuf buf, int locationPacketId, String... imei) { - List<Position> positions = new LinkedList<>(); - - if (!connectionless) { - buf.readUnsignedInt(); // data length - } - - int codec = buf.readUnsignedByte(); - int count = buf.readUnsignedByte(); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - - if (deviceSession == null) { - return null; - } - - for (int i = 0; i < count; i++) { - Position position = new Position(getProtocolName()); - - position.setDeviceId(deviceSession.getDeviceId()); - position.setValid(true); - - if (codec == CODEC_12) { - decodeSerial(channel, remoteAddress, position, buf); - } else { - decodeLocation(position, buf, codec); - } - - if (!position.getOutdated() || !position.getAttributes().isEmpty()) { - positions.add(position); - } - } - - if (channel != null) { - if (connectionless) { - ByteBuf response = Unpooled.buffer(); - response.writeShort(5); - response.writeShort(0); - response.writeByte(0x01); - response.writeByte(locationPacketId); - response.writeByte(count); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } else { - ByteBuf response = Unpooled.buffer(); - response.writeInt(count); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - return positions.isEmpty() ? null : positions; - } - - @Override - protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - if (connectionless) { - return decodeUdp(channel, remoteAddress, buf); - } else { - return decodeTcp(channel, remoteAddress, buf); - } - } - - private Object decodeTcp(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception { - - if (buf.getUnsignedShort(0) > 0) { - parseIdentification(channel, remoteAddress, buf); - } else { - buf.skipBytes(4); - return parseData(channel, remoteAddress, buf, 0); - } - - return null; - } - - private Object decodeUdp(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception { - - buf.readUnsignedShort(); // length - buf.readUnsignedShort(); // packet id - buf.readUnsignedByte(); // packet type - int locationPacketId = buf.readUnsignedByte(); - String imei = buf.readSlice(buf.readUnsignedShort()).toString(StandardCharsets.US_ASCII); - - return parseData(channel, remoteAddress, buf, locationPacketId, imei); - - } - -} |