aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/org/traccar/protocol/AstraProtocolDecoder.java219
-rw-r--r--src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java4
2 files changed, 210 insertions, 13 deletions
diff --git a/src/main/java/org/traccar/protocol/AstraProtocolDecoder.java b/src/main/java/org/traccar/protocol/AstraProtocolDecoder.java
index a7bfd4625..a1e133c23 100644
--- a/src/main/java/org/traccar/protocol/AstraProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AstraProtocolDecoder.java
@@ -16,6 +16,7 @@
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.slf4j.Logger;
@@ -31,6 +32,7 @@ import org.traccar.model.Position;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
+import java.util.Date;
import java.util.LinkedList;
import java.util.List;
@@ -54,20 +56,30 @@ public class AstraProtocolDecoder extends BaseProtocolDecoder {
byte protocol = buf.readByte();
buf.readUnsignedShort(); // length
+ if (channel != null) {
+ channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(new byte[] {0x06}), remoteAddress));
+ }
+
return switch (protocol) {
case 'K' -> decodeK(channel, remoteAddress, buf);
+ case 'X' -> decodeX(channel, remoteAddress, buf);
default -> null;
};
}
- private Object decodeK(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
+ private String readImei(ByteBuf buf) {
+ return String.format("%08d", buf.readUnsignedInt()) + String.format("%07d", buf.readUnsignedMedium());
+ }
- if (channel != null) {
- channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(new byte[] {0x06}), remoteAddress));
- }
+ private Date readTime(ByteBuf buf) {
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(1980, 1, 6).addMillis(buf.readUnsignedInt() * 1000L);
+ return dateBuilder.getDate();
+ }
- String imei = String.format("%08d", buf.readUnsignedInt()) + String.format("%07d", buf.readUnsignedMedium());
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
+ private Object decodeK(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, readImei(buf));
if (deviceSession == null) {
return null;
}
@@ -84,11 +96,7 @@ public class AstraProtocolDecoder extends BaseProtocolDecoder {
position.setValid(true);
position.setLatitude(buf.readInt() * 0.000001);
position.setLongitude(buf.readInt() * 0.000001);
-
- DateBuilder dateBuilder = new DateBuilder()
- .setDate(1980, 1, 6).addMillis(buf.readUnsignedInt() * 1000L);
- position.setTime(dateBuilder.getDate());
-
+ position.setTime(readTime(buf));
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte() * 2));
position.setCourse(buf.readUnsignedByte() * 2);
@@ -134,4 +142,193 @@ public class AstraProtocolDecoder extends BaseProtocolDecoder {
return positions;
}
+ private Object decodeX(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
+
+ int count = buf.readUnsignedByte();
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, readImei(buf));
+ if (deviceSession == null) {
+ return null;
+ }
+
+ List<Position> positions = new LinkedList<>();
+ for (int i = 0; i < count; i++) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.set(Position.KEY_INDEX, buf.readUnsignedByte());
+ long mask = (long) buf.readUnsignedShort() << 32 + buf.readUnsignedInt();
+ position.setDeviceTime(readTime(buf));
+ position.set(Position.KEY_EVENT, buf.readUnsignedInt());
+ position.set(Position.KEY_STATUS, buf.readUnsignedShort());
+
+ if ((mask & 1L) > 0) {
+ position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.2);
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ }
+
+ if ((mask & 2L) > 0) {
+ position.setValid(true);
+ position.setFixTime(readTime(buf));
+ position.setLatitude(buf.readInt() * 0.000001);
+ position.setLongitude(buf.readInt() * 0.000001);
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte() * 2));
+ buf.readUnsignedByte(); // max speed since last report
+ position.setCourse(buf.readUnsignedByte() * 2);
+ position.setAltitude(buf.readUnsignedByte() * 20);
+ position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedShort() * 100);
+ } else {
+ getLastLocation(position, position.getDeviceTime());
+ }
+
+ if ((mask & 4L) > 0) {
+ buf.readUnsignedShort(); // states
+ buf.readUnsignedShort(); // changes mask
+ }
+
+ if ((mask & 8L) > 0) {
+ buf.readUnsignedShort(); // adc1
+ buf.readUnsignedShort(); // adc2
+ }
+
+ if ((mask & 16L) > 0) {
+ position.set("xMax", buf.readByte());
+ position.set("xMin", buf.readByte());
+ position.set("yMax", buf.readByte());
+ position.set("yMin", buf.readByte());
+ position.set("zMax", buf.readByte());
+ position.set("zMin", buf.readByte());
+ position.set("idleHours", buf.readUnsignedShort());
+ }
+
+ if ((mask & 32L) > 0) {
+ int value = buf.readUnsignedByte();
+ position.set(Position.KEY_SATELLITES, BitUtil.to(value, 4));
+ position.set(Position.KEY_RSSI, BitUtil.from(value, 4));
+ }
+
+ if ((mask & 64L) > 0) {
+ buf.readUnsignedShort(); // mcc
+ buf.readUnsignedShort(); // mnc
+ }
+
+ if ((mask & 128L) > 0) {
+ buf.readUnsignedByte(); // geofences
+ }
+
+ if ((mask & 256L) > 0) {
+ buf.readUnsignedByte(); // source
+ buf.readLong(); // driver id
+ }
+
+ if ((mask & 512L) > 0) {
+ buf.readUnsignedByte(); // source
+ buf.skipBytes(10); // trailer id
+ buf.readUnsignedByte(); // status
+ }
+
+ if ((mask & 1024L) > 0) {
+ position.set("axleWeight", buf.readUnsignedShort());
+ }
+
+ if ((mask & 2048L) > 0) {
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium() * 1000);
+ position.set(Position.KEY_HOURS, buf.readUnsignedShort() * 3_600_000);
+ }
+
+ if ((mask & 4096L) > 0) {
+ position.set("wheelSpeedMax", buf.readUnsignedByte());
+ position.set("wheelSpeedAvg", buf.readUnsignedByte());
+ position.set("rpmMax", buf.readUnsignedByte() * 32);
+ position.set("rpmAvg", buf.readUnsignedByte() * 32);
+ position.set("acceleratorMax", buf.readUnsignedByte());
+ position.set("acceleratorAvg", buf.readUnsignedByte());
+ position.set("engineLoadMax", buf.readUnsignedByte());
+ position.set("engineLoadAvg", buf.readUnsignedByte());
+ position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedShort() * 100);
+ position.set(Position.KEY_COOLANT_TEMP, buf.readByte() + 40);
+ position.set("fmsStatus", buf.readUnsignedShort());
+ position.set("fmsEvents", buf.readUnsignedShort());
+ position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte());
+ position.set(Position.KEY_FUEL_USED, buf.readUnsignedInt() * 0.5);
+ }
+
+ if ((mask & 8192L) > 0) {
+ position.set("wheelSpeedMax", buf.readUnsignedByte());
+ position.set("wheelSpeedAvg", buf.readUnsignedByte());
+ position.set("rpmMax", buf.readUnsignedByte() * 32);
+ position.set("rpmAvg", buf.readUnsignedByte() * 32);
+ position.set("acceleratorMax", buf.readUnsignedByte());
+ position.set("acceleratorAvg", buf.readUnsignedByte());
+ position.set("engineLoadMax", buf.readUnsignedByte());
+ position.set("engineLoadAvg", buf.readUnsignedByte());
+ position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedShort() * 100);
+ position.set(Position.KEY_COOLANT_TEMP, buf.readByte() + 40);
+ position.set("obdStatus", buf.readUnsignedShort());
+ position.set("obdEvents", buf.readUnsignedShort());
+ position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte());
+ position.set(Position.KEY_FUEL_USED, buf.readUnsignedShort() * 0.1);
+ }
+
+ if ((mask & 16384L) > 0) {
+ for (int j = 1; j <= 5; j++) {
+ position.set("dtc" + j, buf.readCharSequence(5, StandardCharsets.US_ASCII).toString());
+ }
+ }
+
+ if ((mask & 32768L) > 0) {
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium() * 1000);
+ position.set(Position.KEY_HOURS, buf.readUnsignedShort() * 3_600_000);
+ position.set("axleWeight", buf.readUnsignedShort());
+ position.set("tripFuelUsed", buf.readUnsignedShort() * 0.1);
+ position.set("tripCruise", buf.readUnsignedShort());
+ position.set(Position.KEY_ODOMETER_SERVICE, buf.readUnsignedShort() * 5);
+ }
+
+ if ((mask & 65536L) > 0) {
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium() * 1000);
+ position.set(Position.KEY_HOURS, buf.readUnsignedShort() * 3_600_000);
+ buf.readUnsignedShort(); // time with mil on
+ buf.readUnsignedShort(); // distance with mil on
+ }
+
+ if ((mask & 131072L) > 0) {
+ for (int j = 1; j <= 6; j++) {
+ position.set(Position.PREFIX_TEMP + j, buf.readShort() * 0.1);
+ }
+ for (int j = 1; j <= 3; j++) {
+ position.set("setpoint" + j, buf.readByte() * 0.5);
+ }
+ buf.readUnsignedByte(); // refrigerator fuel level
+ buf.readUnsignedShort(); // refrigerator total engine hours
+ buf.readUnsignedShort(); // refrigerator total standby hours
+ buf.readUnsignedShort(); // refrigerator status
+ buf.readUnsignedMedium(); // alarm flags
+ }
+
+ if ((mask & 262144L) > 0) {
+ for (int j = 1; j <= 4; j++) {
+ position.set(Position.PREFIX_TEMP + j, (buf.readUnsignedShort() - 550) * 0.1);
+ }
+ }
+
+ if ((mask & 524288L) > 0) {
+ position.set("alarmCount", buf.readUnsignedByte());
+ position.set("alarmQueue", ByteBufUtil.hexDump(buf.readSlice(16)));
+ }
+
+ if ((mask & 4294967296L) > 0) {
+ for (int j = 1; j <= 6; j++) {
+ position.set("sensor" + j, buf.readUnsignedMedium());
+ }
+ }
+
+ positions.add(position);
+
+ }
+
+ return positions;
+ }
+
}
diff --git a/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java
index cf1978f4e..dc48fc829 100644
--- a/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java
@@ -10,8 +10,8 @@ public class AstraProtocolDecoderTest extends ProtocolTest {
var decoder = inject(new AstraProtocolDecoder(null));
- verifyNull(decoder, binary(
- "58003d018b0000000000bf514f00b70000006000093e60514f00b6032fec49ffdc7627000041020000000100010000000000090001010000008f00aba3"));
+ verifyPositions(decoder, false, binary(
+ "5800cb02052196881aff5b3c0000200010bf53cbfab10000000100393d5853cbfab0031b93affffb034b0000ae00000000010000000c000c00000000000000787e00000000000000000000000000000000000000000000000000000000000000000000000000000000003d0000200010bf53cbfae60000280000293c5853cbfae6031b93affffb034b0000ae00000000010000000d000c00000000000000ae7e0000000000000000000000000000000000000000000000000000000000000000000000000000000000e604"));
verifyPositions(decoder, binary(
"4b00700529c0c265976b8202cba9ff00676d864554a9c30000000020073401006436000300030008000000000000a0000100001920c43d00009600428302cba9ff00676d864554aa3e000000002007240100643b000300020008000000000000b0000100001920c43d00009600420f0e"));