diff options
Diffstat (limited to 'src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java')
-rw-r--r-- | src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 120 |
1 files changed, 94 insertions, 26 deletions
diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 929eca8aa..6197c6c13 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2023 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. @@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; -import org.traccar.model.Device; +import org.traccar.helper.BufferUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -33,6 +33,7 @@ import org.traccar.model.Network; import org.traccar.model.Position; import java.net.SocketAddress; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.HashMap; @@ -112,18 +113,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } } - private boolean isPrintable(ByteBuf buf, int length) { - boolean printable = true; - for (int i = 0; i < length; i++) { - byte b = buf.getByte(buf.readerIndex() + i); - if (b < 32 && b != '\r' && b != '\n') { - printable = false; - break; - } - } - return printable; - } - private void decodeSerial( Channel channel, SocketAddress remoteAddress, DeviceSession deviceSession, Position position, ByteBuf buf) { @@ -169,7 +158,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_TYPE, type); int length = buf.readInt(); - if (isPrintable(buf, length)) { + if (BufferUtil.isPrintable(buf, length)) { String data = buf.readSlice(length).toString(StandardCharsets.US_ASCII).trim(); if (data.startsWith("UUUUww") && data.endsWith("SSS")) { String[] values = data.substring(6, data.length() - 4).split(";"); @@ -231,6 +220,8 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(26, null, (p, b) -> p.set("bleTemp2", b.readShort() * 0.01)); register(27, null, (p, b) -> p.set("bleTemp3", b.readShort() * 0.01)); register(28, null, (p, b) -> p.set("bleTemp4", b.readShort() * 0.01)); + register(30, fmbXXX, (p, b) -> p.set("faultCount", b.readUnsignedByte())); + register(32, fmbXXX, (p, b) -> p.set(Position.KEY_COOLANT_TEMP, b.readByte())); register(66, null, (p, b) -> p.set(Position.KEY_POWER, b.readUnsignedShort() * 0.001)); register(67, null, (p, b) -> p.set(Position.KEY_BATTERY, b.readUnsignedShort() * 0.001)); register(68, fmbXXX, (p, b) -> p.set("batteryCurrent", b.readUnsignedShort() * 0.001)); @@ -239,28 +230,52 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(74, fmbXXX, (p, b) -> p.set(Position.PREFIX_TEMP + 3, b.readInt() * 0.1)); register(75, fmbXXX, (p, b) -> p.set(Position.PREFIX_TEMP + 4, b.readInt() * 0.1)); register(78, null, (p, b) -> { - long driverUniqueId = b.readLong(); + long driverUniqueId = b.readLongLE(); if (driverUniqueId > 0) { p.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", driverUniqueId)); } }); register(80, fmbXXX, (p, b) -> p.set("dataMode", b.readUnsignedByte())); + register(81, fmbXXX, (p, b) -> p.set(Position.KEY_OBD_SPEED, b.readUnsignedByte())); + register(82, fmbXXX, (p, b) -> p.set(Position.KEY_THROTTLE, b.readUnsignedByte())); + register(83, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_USED, b.readUnsignedInt() * 0.1)); + register(84, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_LEVEL, b.readUnsignedShort() * 0.1)); + register(85, fmbXXX, (p, b) -> p.set(Position.KEY_RPM, b.readUnsignedShort())); + register(87, fmbXXX, (p, b) -> p.set(Position.KEY_OBD_ODOMETER, b.readUnsignedInt())); + register(89, fmbXXX, (p, b) -> p.set("fuelLevelPercentage", b.readUnsignedByte())); register(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort())); - register(115, fmbXXX, (p, b) -> p.set(Position.KEY_COOLANT_TEMP, b.readShort() * 0.1)); + register(110, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_CONSUMPTION, b.readUnsignedShort() * 0.1)); + register(113, fmbXXX, (p, b) -> p.set(Position.KEY_BATTERY_LEVEL, b.readUnsignedByte())); register(179, null, (p, b) -> p.set(Position.PREFIX_OUT + 1, b.readUnsignedByte() > 0)); register(180, null, (p, b) -> p.set(Position.PREFIX_OUT + 2, b.readUnsignedByte() > 0)); register(181, null, (p, b) -> p.set(Position.KEY_PDOP, b.readUnsignedShort() * 0.1)); register(182, null, (p, b) -> p.set(Position.KEY_HDOP, b.readUnsignedShort() * 0.1)); register(199, null, (p, b) -> p.set(Position.KEY_ODOMETER_TRIP, b.readUnsignedInt())); register(200, fmbXXX, (p, b) -> p.set("sleepMode", b.readUnsignedByte())); - register(205, fmbXXX, (p, b) -> p.set("cid", b.readUnsignedShort())); + register(205, fmbXXX, (p, b) -> p.set("cid2g", b.readUnsignedShort())); register(206, fmbXXX, (p, b) -> p.set("lac", b.readUnsignedShort())); + register(232, fmbXXX, (p, b) -> p.set("cngStatus", b.readUnsignedByte() > 0)); + register(233, fmbXXX, (p, b) -> p.set("cngUsed", b.readUnsignedInt() * 0.1)); + register(234, fmbXXX, (p, b) -> p.set("cngLevel", b.readUnsignedShort())); + register(235, fmbXXX, (p, b) -> p.set("oilLevel", b.readUnsignedByte())); register(236, null, (p, b) -> { p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_GENERAL : null); }); register(239, null, (p, b) -> p.set(Position.KEY_IGNITION, b.readUnsignedByte() > 0)); register(240, null, (p, b) -> p.set(Position.KEY_MOTION, b.readUnsignedByte() > 0)); register(241, null, (p, b) -> p.set(Position.KEY_OPERATOR, b.readUnsignedInt())); + register(246, fmbXXX, (p, b) -> { + p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_TOW : null); + }); + register(247, fmbXXX, (p, b) -> { + p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_ACCIDENT : null); + }); + register(249, fmbXXX, (p, b) -> { + p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_JAMMING : null); + }); + register(252, fmbXXX, (p, b) -> { + p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_POWER_CUT : null); + }); register(253, null, (p, b) -> { switch (b.readUnsignedByte()) { case 1: @@ -276,6 +291,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { break; } }); + register(636, fmbXXX, (p, b) -> p.set("cid4g", b.readUnsignedInt())); } private void decodeGh3000Parameter(Position position, int id, ByteBuf buf, int length) { @@ -366,14 +382,23 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { position.setNetwork(network); } } else { - Integer cid = (Integer) position.getAttributes().remove("cid"); + Integer cid2g = (Integer) position.getAttributes().remove("cid2g"); + Long cid4g = (Long) position.getAttributes().remove("cid4g"); Integer lac = (Integer) position.getAttributes().remove("lac"); - if (cid != null && lac != null) { - CellTower cellTower = CellTower.fromLacCid(getConfig(), lac, cid); + if (lac != null && (cid2g != null || cid4g != null)) { + Network network = new Network(); + CellTower cellTower; + if (cid2g != null) { + cellTower = CellTower.fromLacCid(getConfig(), lac, cid2g); + } else { + cellTower = CellTower.fromLacCid(getConfig(), lac, cid4g); + network.setRadioType("lte"); + } long operator = position.getInteger(Position.KEY_OPERATOR); if (operator >= 1000) { cellTower.setOperator(operator); } + network.addCellTower(cellTower); position.setNetwork(new Network(cellTower)); } } @@ -563,6 +588,38 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } index += 1; } + } else if (id == 548 || id == 10829 || id == 10831) { + ByteBuf data = buf.readSlice(length); + data.readUnsignedByte(); // header + for (int i = 1; data.isReadable(); i++) { + ByteBuf beacon = data.readSlice(data.readUnsignedByte()); + while (beacon.isReadable()) { + int parameterId = beacon.readUnsignedByte(); + int parameterLength = beacon.readUnsignedByte(); + switch (parameterId) { + case 0: + position.set("tag" + i + "Rssi", (int) beacon.readByte()); + break; + case 1: + String beaconId = ByteBufUtil.hexDump(beacon.readSlice(parameterLength)); + position.set("tag" + i + "Id", beaconId); + break; + case 2: + String beaconData = ByteBufUtil.hexDump(beacon.readSlice(parameterLength)); + position.set("tag" + i + "Data", beaconData); + break; + case 13: + position.set("tag" + i + "LowBattery", beacon.readUnsignedByte()); + break; + case 14: + position.set("tag" + i + "Battery", beacon.readUnsignedShort()); + break; + default: + beacon.skipBytes(parameterLength); + break; + } + } + } } else { position.set(Position.PREFIX_IO + id, ByteBufUtil.hexDump(buf.readSlice(length))); } @@ -571,6 +628,14 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { decodeNetwork(position, model); + if (model != null && model.matches("FM.6..")) { + Long driverMsb = (Long) position.getAttributes().get("io195"); + Long driverLsb = (Long) position.getAttributes().get("io196"); + if (driverMsb != null && driverLsb != null) { + String driver = new String(ByteBuffer.allocate(16).putLong(driverMsb).putLong(driverLsb).array()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, driver); + } + } } private List<Position> parseData( @@ -588,7 +653,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { if (deviceSession == null) { return null; } - String model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel(); for (int i = 0; i < count; i++) { Position position = new Position(getProtocolName()); @@ -600,9 +664,13 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // type int length = buf.readInt() - 4; getLastLocation(position, new Date(buf.readUnsignedInt() * 1000)); - if (isPrintable(buf, length)) { - position.set(Position.KEY_RESULT, - buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim()); + if (BufferUtil.isPrintable(buf, length)) { + String data = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim(); + if (data.startsWith("GTSL")) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, data.split("\\|")[4]); + } else { + position.set(Position.KEY_RESULT, data); + } } else { position.set(Position.KEY_RESULT, ByteBufUtil.hexDump(buf.readSlice(length))); @@ -610,7 +678,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } else if (codec == CODEC_12) { decodeSerial(channel, remoteAddress, deviceSession, position, buf); } else { - decodeLocation(position, buf, codec, model); + decodeLocation(position, buf, codec, getDeviceModel(deviceSession)); } if (!position.getOutdated() || !position.getAttributes().isEmpty()) { |