Decode GoSafe binary format

This commit is contained in:
Anton Tananaev 2024-12-09 07:43:53 -08:00
parent 1369b7d91f
commit ed531cf336
2 changed files with 113 additions and 5 deletions

View File

@ -35,6 +35,7 @@ import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;
@ -69,7 +70,7 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder {
.any()
.compile();
private void decodeFragment(Position position, String fragment) {
private void decodeTextFragment(Position position, String fragment) {
int dataIndex = fragment.indexOf(':');
int index = 0;
@ -182,7 +183,7 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder {
}
}
private Position decodePosition(DeviceSession deviceSession, String sentence) throws ParseException {
private Position decodeTextPosition(DeviceSession deviceSession, String sentence) throws ParseException {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
@ -202,7 +203,7 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder {
if (fragments[index].matches("\\p{XDigit}+")) {
position.set(Position.KEY_EVENT, Integer.parseInt(fragments[index], 16));
} else {
decodeFragment(position, fragments[index]);
decodeTextFragment(position, fragments[index]);
}
}
}
@ -220,7 +221,17 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder {
}
ByteBuf buf = (ByteBuf) msg;
String sentence = buf.toString(StandardCharsets.US_ASCII);
char marker = (char) buf.getByte(buf.readerIndex());
if (marker == '*') {
return decodeText(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII));
} else {
return decodeBinary(channel, remoteAddress, buf);
}
}
private Object decodeText(
Channel channel, SocketAddress remoteAddress, String sentence) throws Exception {
Pattern pattern = PATTERN;
if (sentence.startsWith("*GS02")) {
pattern = PATTERN_OLD;
@ -261,11 +272,105 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder {
List<Position> positions = new LinkedList<>();
for (String item : parser.next().split("\\$")) {
positions.add(decodePosition(deviceSession, item));
positions.add(decodeTextPosition(deviceSession, item));
}
return positions;
}
}
private Object decodeBinary(
Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception {
buf.readUnsignedByte(); // header
buf.readUnsignedByte(); // protocol version
int type = buf.readUnsignedByte();
String imei = String.valueOf((buf.readUnsignedInt() << (3 * 8)) | buf.readUnsignedMedium());
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
if (deviceSession == null) {
return null;
}
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
long seconds = buf.readUnsignedInt() + 946684800L; // from 2000-01-01
position.setTime(new Date(seconds * 1000));
if (type == 0x41) {
buf.readUnsignedByte(); // event id
}
int mask = buf.readUnsignedShort();
if (BitUtil.check(mask, 0)) {
buf.skipBytes(buf.readUnsignedByte()); // SYS
}
if (BitUtil.check(mask, 1)) {
buf.readUnsignedByte(); // length
int fragmentMask = buf.readUnsignedShort();
if (BitUtil.check(fragmentMask, 0)) {
int flags = buf.readUnsignedByte();
position.setValid(BitUtil.between(flags, 5, 7) > 0);
position.set(Position.KEY_SATELLITES, BitUtil.to(flags, 5));
}
if (BitUtil.check(fragmentMask, 1)) {
position.setLatitude(buf.readInt() / 1000000.0);
position.setLongitude(buf.readInt() / 1000000.0);
}
if (BitUtil.check(fragmentMask, 2)) {
position.setSpeed(UnitsConverter.knotsFromKph(buf.readShort()));
}
if (BitUtil.check(fragmentMask, 3)) {
position.setCourse(buf.readUnsignedShort());
}
if (BitUtil.check(fragmentMask, 4)) {
position.setAltitude(buf.readShort());
}
if (BitUtil.check(fragmentMask, 5)) {
position.set(Position.KEY_HDOP, buf.readUnsignedShort() / 100.0);
}
if (BitUtil.check(fragmentMask, 6)) {
position.set(Position.KEY_VDOP, buf.readUnsignedShort() / 100.0);
}
} else {
getLastLocation(position, position.getDeviceTime());
}
if (BitUtil.check(mask, 2)) {
buf.skipBytes(buf.readUnsignedByte()); // GSM
}
if (BitUtil.check(mask, 3)) {
buf.skipBytes(buf.readUnsignedByte()); // COT
}
if (BitUtil.check(mask, 4)) {
buf.skipBytes(buf.readUnsignedByte()); // ADC
}
if (BitUtil.check(mask, 5)) {
buf.skipBytes(buf.readUnsignedByte()); // DTT
}
if (BitUtil.check(mask, 6)) {
buf.skipBytes(buf.readUnsignedByte()); // IWD
}
if (BitUtil.check(mask, 7)) {
buf.skipBytes(buf.readUnsignedByte()); // ETD
}
return position;
}
}

View File

@ -11,6 +11,9 @@ public class GoSafeProtocolDecoderTest extends ProtocolTest {
var decoder = inject(new GoSafeProtocolDecoder(null));
verifyPosition(decoder, binary(
"f80601013fb82203661b2ee46249007a13003f45feefeeb401db1bbe00000000060e00d602018904036412080c010111e121003100410051010807000000000000004655f8"));
verifyPositions(decoder, false, buffer(
"*GS06,357330050846344,RST#"));