aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org')
-rw-r--r--src/main/java/org/traccar/database/StatisticsManager.java4
-rw-r--r--src/main/java/org/traccar/protocol/AstraProtocolDecoder.java219
-rw-r--r--src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java55
3 files changed, 249 insertions, 29 deletions
diff --git a/src/main/java/org/traccar/database/StatisticsManager.java b/src/main/java/org/traccar/database/StatisticsManager.java
index d13f72793..5f4d97263 100644
--- a/src/main/java/org/traccar/database/StatisticsManager.java
+++ b/src/main/java/org/traccar/database/StatisticsManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 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.
@@ -100,8 +100,6 @@ public class StatisticsManager {
statistics.setProtocols(protocols);
}
- statistics.set("modern", config.getString(Keys.WEB_PATH).contains("modern"));
-
users.clear();
deviceProtocols.clear();
deviceMessages.clear();
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/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java
index c18b29288..524d86289 100644
--- a/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java
@@ -141,6 +141,7 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_OBD_RT = 0x9901;
public static final int MSG_OBD_RTA = 0x9902;
+ public static final int MSG_DTC = 0x9903;
public static final int MSG_TRACK_ON_DEMAND = 0x4101;
public static final int MSG_TRACK_BY_INTERVAL = 0x4102;
@@ -208,20 +209,36 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
}
}
- private String decodeAlarm(short value) {
- return switch (value) {
- case 0x01 -> Position.ALARM_SOS;
- case 0x10 -> Position.ALARM_LOW_BATTERY;
- case 0x11 -> Position.ALARM_OVERSPEED;
- case 0x12 -> Position.ALARM_MOVEMENT;
- case 0x13 -> Position.ALARM_GEOFENCE_ENTER;
- case 0x14 -> Position.ALARM_ACCIDENT;
- case 0x50 -> Position.ALARM_POWER_OFF;
- case 0x53 -> Position.ALARM_GPS_ANTENNA_CUT;
- case 0x72 -> Position.ALARM_BRAKING;
- case 0x73 -> Position.ALARM_ACCELERATION;
- default -> null;
- };
+ private String decodeAlarm(String model, short value) {
+ if ("TK218".equals(model)) {
+ return switch (value) {
+ case 0x01 -> Position.ALARM_SOS;
+ case 0x10 -> Position.ALARM_LOW_BATTERY;
+ case 0x11 -> Position.ALARM_OVERSPEED;
+ case 0x12 -> Position.ALARM_MOVEMENT;
+ case 0x13 -> Position.ALARM_GEOFENCE;
+ case 0x60 -> Position.ALARM_FATIGUE_DRIVING;
+ case 0x71 -> Position.ALARM_BRAKING;
+ case 0x72 -> Position.ALARM_ACCELERATION;
+ case 0x73 -> Position.ALARM_ACCIDENT;
+ case 0x74 -> Position.ALARM_IDLE;
+ default -> null;
+ };
+ } else {
+ return switch (value) {
+ case 0x01 -> Position.ALARM_SOS;
+ case 0x10 -> Position.ALARM_LOW_BATTERY;
+ case 0x11 -> Position.ALARM_OVERSPEED;
+ case 0x12 -> Position.ALARM_MOVEMENT;
+ case 0x13 -> Position.ALARM_GEOFENCE_ENTER;
+ case 0x14 -> Position.ALARM_ACCIDENT;
+ case 0x50 -> Position.ALARM_POWER_OFF;
+ case 0x53 -> Position.ALARM_GPS_ANTENNA_CUT;
+ case 0x72 -> Position.ALARM_BRAKING;
+ case 0x73 -> Position.ALARM_ACCELERATION;
+ default -> null;
+ };
+ }
}
private Position decodeRegular(Position position, String sentence) {
@@ -341,6 +358,12 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Position decodeDtc(Position position, String sentence) {
+ getLastLocation(position, null);
+ position.set(Position.KEY_DTCS, sentence.replace(',', ' '));
+ return position;
+ }
+
private List<Position> decodeRetransmission(ByteBuf buf, DeviceSession deviceSession) {
List<Position> positions = new LinkedList<>();
@@ -437,7 +460,8 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
if (command == MSG_ALARM) {
short alarmCode = buf.readUnsignedByte();
- position.set(Position.KEY_ALARM, decodeAlarm(alarmCode));
+ String model = getDeviceModel(deviceSession);
+ position.set(Position.KEY_ALARM, decodeAlarm(model, alarmCode));
if (alarmCode >= 0x02 && alarmCode <= 0x05) {
position.set(Position.PREFIX_IN + alarmCode, 1);
} else if (alarmCode >= 0x32 && alarmCode <= 0x35) {
@@ -473,6 +497,7 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
case MSG_RFID -> decodeRfid(position, sentence);
case MSG_OBD_RT -> decodeObd(position, sentence);
case MSG_OBD_RTA -> decodeObdA(position, sentence);
+ case MSG_DTC -> decodeDtc(position, sentence);
default -> null;
};