aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java')
-rw-r--r--src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java283
1 files changed, 266 insertions, 17 deletions
diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
index d0bbeebb5..0a8540543 100644
--- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -131,7 +131,10 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(value, 8)) {
return Position.ALARM_POWER_OFF;
}
- if (BitUtil.check(value, 17)) {
+ if (BitUtil.check(value, 15)) {
+ return Position.ALARM_VIBRATION;
+ }
+ if (BitUtil.check(value, 16) || BitUtil.check(value, 17)) {
return Position.ALARM_TAMPERING;
}
if (BitUtil.check(value, 20)) {
@@ -140,7 +143,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(value, 28)) {
return Position.ALARM_MOVEMENT;
}
- if (BitUtil.check(value, 29)) {
+ if (BitUtil.check(value, 29) || BitUtil.check(value, 30)) {
return Position.ALARM_ACCIDENT;
}
return null;
@@ -169,7 +172,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
} else {
long imei = id.getUnsignedShort(0);
imei = (imei << 32) + id.getUnsignedInt(2);
- return String.valueOf(imei);
+ return String.valueOf(imei) + Checksum.luhn(imei);
}
}
@@ -294,6 +297,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
} else if (type == MSG_TRANSPARENT) {
+ sendGeneralResponse(channel, remoteAddress, id, type, index);
+
return decodeTransparent(deviceSession, buf);
}
@@ -327,6 +332,16 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
case 0x03:
position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() * 0.1);
break;
+ case 0x56:
+ buf.readUnsignedByte(); // power level
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ break;
+ case 0x61:
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
+ break;
+ case 0x69:
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
+ break;
case 0x80:
position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte());
break;
@@ -388,6 +403,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
int status = buf.readInt();
position.set(Position.KEY_IGNITION, BitUtil.check(status, 0));
+ position.set(Position.KEY_MOTION, BitUtil.check(status, 4));
position.set(Position.KEY_BLOCKED, BitUtil.check(status, 10));
position.set(Position.KEY_CHARGE, BitUtil.check(status, 26));
@@ -448,6 +464,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
int subtype = buf.readUnsignedByte();
int length = buf.readUnsignedByte();
int endIndex = buf.readerIndex() + length;
+ String stringValue;
switch (subtype) {
case 0x01:
position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100);
@@ -455,8 +472,12 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
case 0x02:
position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShort() * 0.1);
break;
+ case 0x25:
+ position.set(Position.KEY_INPUT, buf.readUnsignedInt());
+ break;
case 0x2b:
- position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt());
+ position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort());
+ position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort());
break;
case 0x30:
position.set(Position.KEY_RSSI, buf.readUnsignedByte());
@@ -465,12 +486,75 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
break;
case 0x33:
- String sentence = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
- if (sentence.startsWith("*M00")) {
- String lockStatus = sentence.substring(8, 8 + 7);
+ stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ if (stringValue.startsWith("*M00")) {
+ String lockStatus = stringValue.substring(8, 8 + 7);
position.set(Position.KEY_BATTERY, Integer.parseInt(lockStatus.substring(2, 5)) * 0.01);
}
break;
+ case 0x56:
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 10);
+ buf.readUnsignedByte(); // reserved
+ break;
+ case 0x57:
+ int alarm = buf.readUnsignedShort();
+ position.set(Position.KEY_ALARM, BitUtil.check(alarm, 8) ? Position.ALARM_ACCELERATION : null);
+ position.set(Position.KEY_ALARM, BitUtil.check(alarm, 9) ? Position.ALARM_BRAKING : null);
+ position.set(Position.KEY_ALARM, BitUtil.check(alarm, 10) ? Position.ALARM_CORNERING : null);
+ buf.readUnsignedShort(); // external switch state
+ buf.skipBytes(4); // reserved
+ break;
+ case 0x60:
+ int event = buf.readUnsignedShort();
+ position.set(Position.KEY_EVENT, event);
+ if (event >= 0x0061 && event <= 0x0066) {
+ buf.skipBytes(6); // lock id
+ stringValue = buf.readCharSequence(8, StandardCharsets.US_ASCII).toString();
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, stringValue);
+ }
+ break;
+ case 0x63:
+ for (int i = 1; i <= length / 11; i++) {
+ position.set("lock" + i + "Id", ByteBufUtil.hexDump(buf.readSlice(6)));
+ position.set("lock" + i + "Battery", buf.readUnsignedShort() * 0.001);
+ position.set("lock" + i + "Seal", buf.readUnsignedByte() == 0x31);
+ buf.readUnsignedByte(); // physical state
+ buf.readUnsignedByte(); // rssi
+ }
+ break;
+ case 0x64:
+ buf.readUnsignedInt(); // alarm serial number
+ buf.readUnsignedByte(); // alarm status
+ position.set("adasAlarm", buf.readUnsignedByte());
+ break;
+ case 0x65:
+ buf.readUnsignedInt(); // alarm serial number
+ buf.readUnsignedByte(); // alarm status
+ position.set("dmsAlarm", buf.readUnsignedByte());
+ break;
+ case 0x70:
+ buf.readUnsignedInt(); // alarm serial number
+ buf.readUnsignedByte(); // alarm status
+ switch (buf.readUnsignedByte()) {
+ case 0x01:
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
+ break;
+ case 0x02:
+ position.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
+ break;
+ case 0x03:
+ position.set(Position.KEY_ALARM, Position.ALARM_CORNERING);
+ break;
+ case 0x16:
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT);
+ break;
+ default:
+ break;
+ }
+ break;
+ case 0x69:
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
+ break;
case 0x80:
buf.readUnsignedByte(); // content
endIndex = buf.writerIndex() - 2;
@@ -492,8 +576,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
break;
case 0x94:
if (length > 0) {
- position.set(
- Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString());
+ stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ position.set(Position.KEY_VIN, stringValue);
}
break;
case 0xA7:
@@ -503,6 +587,14 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
case 0xAC:
position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
break;
+ case 0xBC:
+ stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ position.set("driver", stringValue.trim());
+ break;
+ case 0xBD:
+ stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, stringValue);
+ break;
case 0xD0:
long userStatus = buf.readUnsignedInt();
if (BitUtil.check(userStatus, 3)) {
@@ -513,7 +605,12 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1);
break;
case 0xD4:
- position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ case 0xE1:
+ if (length == 1) {
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ } else {
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readUnsignedInt()));
+ }
break;
case 0xD5:
if (length == 2) {
@@ -536,6 +633,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_MOTION, BitUtil.check(deviceStatus, 2));
position.set("cover", BitUtil.check(deviceStatus, 3));
break;
+ case 0xE2:
+ position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedInt() * 0.1);
+ break;
case 0xE6:
while (buf.readerIndex() < endIndex) {
int sensorIndex = buf.readUnsignedByte();
@@ -589,8 +689,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
}
break;
case 0xED:
- String license = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim();
- position.set("driverLicense", license);
+ stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ position.set(Position.KEY_CARD, stringValue.trim());
break;
case 0xEE:
position.set(Position.KEY_RSSI, buf.readUnsignedByte());
@@ -663,6 +763,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
case 0xFE:
if (length == 1) {
position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ } else if (length == 2) {
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1);
} else {
int mark = buf.readUnsignedByte();
if (mark == 0x7C) {
@@ -721,12 +823,15 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
int battery = buf.readUnsignedByte();
if (battery <= 100) {
position.set(Position.KEY_BATTERY_LEVEL, battery);
- } else if (battery == 0xAA) {
+ } else if (battery == 0xAA || battery == 0xAB) {
position.set(Position.KEY_CHARGE, true);
}
- position.setNetwork(new Network(CellTower.fromCidLac(
- getConfig(), buf.readUnsignedInt(), buf.readUnsignedShort())));
+ long cid = buf.readUnsignedInt();
+ int lac = buf.readUnsignedShort();
+ if (cid > 0 && lac > 0) {
+ position.setNetwork(new Network(CellTower.fromCidLac(getConfig(), cid, lac)));
+ }
int product = buf.readUnsignedByte();
int status = buf.readUnsignedShort();
@@ -738,6 +843,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
}
} else if (product == 3) {
position.set(Position.KEY_BLOCKED, BitUtil.check(status, 5));
+ if (BitUtil.check(alarm, 0)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED);
+ }
if (BitUtil.check(alarm, 1)) {
position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER);
}
@@ -747,10 +855,69 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(alarm, 3)) {
position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
}
+ if (BitUtil.check(alarm, 5)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_ENTER);
+ }
+ if (BitUtil.check(alarm, 6)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_EXIT);
+ }
}
position.set(Position.KEY_STATUS, status);
+ while (buf.readableBytes() > 2) {
+ int id = buf.readUnsignedByte();
+ int length = buf.readUnsignedByte();
+ switch (id) {
+ case 0x02:
+ position.setAltitude(buf.readShort());
+ break;
+ case 0x10:
+ position.set("wakeSource", buf.readUnsignedByte());
+ break;
+ case 0x0A:
+ if (length == 3) {
+ buf.readUnsignedShort(); // mcc
+ buf.readUnsignedByte(); // mnc
+ } else {
+ buf.skipBytes(length);
+ }
+ break;
+ case 0x0B:
+ position.set("lockCommand", buf.readUnsignedByte());
+ if (length >= 5 && length <= 6) {
+ position.set("lockCard", buf.readUnsignedInt());
+ } else if (length >= 7) {
+ position.set("lockPassword", buf.readCharSequence(6, StandardCharsets.US_ASCII).toString());
+ }
+ if (length % 2 == 0) {
+ position.set("unlockResult", buf.readUnsignedByte());
+ }
+ break;
+ case 0x0C:
+ int x = buf.readUnsignedShort();
+ if (x > 0x8000) {
+ x -= 0x10000;
+ }
+ int y = buf.readUnsignedShort();
+ if (y > 0x8000) {
+ y -= 0x10000;
+ }
+ int z = buf.readUnsignedShort();
+ if (z > 0x8000) {
+ z -= 0x10000;
+ }
+ position.set("tilt", String.format("[%d,%d,%d]", x, y, z));
+ break;
+ case 0xFC:
+ position.set(Position.KEY_GEOFENCE, buf.readUnsignedByte());
+ break;
+ default:
+ buf.skipBytes(length);
+ break;
+ }
+ }
+
return position;
}
@@ -782,6 +949,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
int type = buf.readUnsignedByte();
if (type == 0xF0) {
+
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
@@ -823,6 +991,34 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
case 0x0539:
position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 0.01);
break;
+ case 0x052B:
+ position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte());
+ break;
+ case 0x052D:
+ position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte() - 40);
+ break;
+ case 0x052E:
+ position.set("airTemp", buf.readUnsignedByte() - 40);
+ break;
+ case 0x0530:
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001);
+ break;
+ case 0x0535:
+ position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x0536:
+ position.set(Position.KEY_RPM, buf.readUnsignedShort());
+ break;
+ case 0x053D:
+ position.set("intakePressure", buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x0544:
+ position.set("liquidLevel", buf.readUnsignedByte());
+ break;
+ case 0x0547:
+ case 0x0548:
+ position.set(Position.KEY_THROTTLE, buf.readUnsignedByte());
+ break;
default:
switch (length) {
case 1:
@@ -841,15 +1037,40 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
break;
}
}
+ getLastLocation(position, time);
+ decodeCoordinates(position, buf);
+ position.setTime(time);
+ break;
+ case 0x02:
+ List<String> codes = new LinkedList<>();
+ count = buf.readUnsignedShort();
+ for (int i = 0; i < count; i++) {
+ buf.readUnsignedInt(); // system id
+ int codeCount = buf.readUnsignedShort();
+ for (int j = 0; j < codeCount; j++) {
+ buf.readUnsignedInt(); // dtc
+ buf.readUnsignedInt(); // status
+ codes.add(buf.readCharSequence(
+ buf.readUnsignedShort(), StandardCharsets.US_ASCII).toString().trim());
+ }
+ }
+ position.set(Position.KEY_DTCS, String.join(" ", codes));
+ getLastLocation(position, time);
decodeCoordinates(position, buf);
position.setTime(time);
break;
case 0x03:
count = buf.readUnsignedByte();
for (int i = 0; i < count; i++) {
- int id = buf.readUnsignedShort();
+ int id = buf.readUnsignedByte();
int length = buf.readUnsignedByte();
switch (id) {
+ case 0x01:
+ position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED);
+ break;
+ case 0x02:
+ position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT);
+ break;
case 0x1A:
position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
break;
@@ -867,11 +1088,21 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
case 0x23:
position.set(Position.KEY_ALARM, Position.ALARM_FATIGUE_DRIVING);
break;
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT);
+ break;
+ case 0x31:
+ case 0x32:
+ position.set(Position.KEY_ALARM, Position.ALARM_DOOR);
+ break;
default:
break;
}
buf.skipBytes(length);
}
+ getLastLocation(position, time);
decodeCoordinates(position, buf);
position.setTime(time);
break;
@@ -886,6 +1117,24 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
}
return position;
+
+ } else if (type == 0xFF) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setValid(true);
+ position.setTime(readDate(buf, deviceSession.get(DeviceSession.KEY_TIMEZONE)));
+ position.setLatitude(buf.readInt() * 0.000001);
+ position.setLongitude(buf.readInt() * 0.000001);
+ position.setAltitude(buf.readShort());
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort() * 0.1));
+ position.setCourse(buf.readUnsignedShort());
+
+ // TODO more positions and g sensor data
+
+ return position;
+
}
return null;