From 132f619e996328c6fcb68d824b63edba69c8a2d6 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 15 Apr 2024 21:34:55 -0700 Subject: Handle Snapper concatenated packet --- .../traccar/protocol/SnapperProtocolDecoder.java | 163 +++++++++++++-------- .../protocol/SnapperProtocolDecoderTest.java | 4 +- 2 files changed, 100 insertions(+), 67 deletions(-) diff --git a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java index 3119e347e..315731c20 100644 --- a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java @@ -33,6 +33,7 @@ import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.text.DateFormat; +import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.TimeZone; @@ -77,6 +78,68 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { } } + private void decodeEvents(Position position, ByteBuf buf) { + + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + buf.readUnsignedByte(); // info 1 + buf.readUnsignedByte(); // info 2 + buf.readUnsignedIntLE(); // timestamp + buf.readUnsignedByte(); // timezone + } + + private void decodeTechInfo(Position position, ByteBuf buf) { + + for (int i = 0; i < 5; i++) { + buf.readUnsignedByte(); // index + int type = buf.readUnsignedByte(); + switch (type) { + case 0x00: + position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.1); + position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + break; + case 0x01: + position.set("interiorTemp", buf.readByte()); + position.set("engineTemp", buf.readByte()); + buf.readUnsignedByte(); // reserved + break; + default: + buf.skipBytes(3); + break; + } + } + } + + private void decodeGpsData(Position position, ByteBuf buf) throws ParseException { + + String content = buf.readCharSequence(buf.readableBytes(), StandardCharsets.US_ASCII).toString(); + JsonObject json = Json.createReader(new StringReader(content)).readObject(); + + DateFormat dateFormat = new SimpleDateFormat("ddMMyyHHmmss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + position.setTime(dateFormat.parse(json.getString("d") + json.getString("t").split("\\.")[0])); + + String lat = json.getString("la"); + position.setLatitude(Integer.parseInt(lat.substring(0, 2)) + Double.parseDouble(lat.substring(2)) / 60); + String lon = json.getString("lo"); + position.setLongitude(Integer.parseInt(lon.substring(0, 3)) + Double.parseDouble(lon.substring(3)) / 60); + + int flags = Integer.parseInt(json.getString("f"), 16); + position.setValid(BitUtil.check(flags, 1)); + if (!BitUtil.check(flags, 6)) { + position.setLatitude(-position.getLatitude()); + } + if (!BitUtil.check(flags, 7)) { + position.setLongitude(-position.getLongitude()); + } + + position.setAltitude(Double.parseDouble(json.getString("a"))); + position.setSpeed(Double.parseDouble(json.getString("s"))); + position.setCourse(Double.parseDouble(json.getString("c"))); + + position.set(Position.KEY_SATELLITES, Integer.parseInt(json.getString("sv"))); + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -94,7 +157,7 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { } buf.readUnsignedShortLE(); // encryption - buf.readUnsignedIntLE(); // length + int length = buf.readIntLE(); buf.readUnsignedByte(); // flags buf.readUnsignedMediumLE(); // reserved int index = buf.readUnsignedShortLE(); @@ -110,71 +173,41 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - if (type == MSG_SEND_EVENTS) { - - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - buf.readUnsignedByte(); // info 1 - buf.readUnsignedByte(); // info 2 - getLastLocation(position, null); // TODO read timestamp - return position; - - } else if (type == MSG_SEND_TECH_INFO) { - - buf.readUnsignedByte(); // index - int subtype = buf.readUnsignedByte(); - switch (subtype) { - case 0x00: - position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.1); - position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - break; - case 0x01: - position.set("interiorTemp", buf.readByte()); - position.set("engineTemp", buf.readByte()); - default: - break; - } - getLastLocation(position, null); - return position; - - } else if (type == MSG_SEND_GPS_DATA) { - - String content = buf.readCharSequence(buf.readableBytes(), StandardCharsets.US_ASCII).toString(); - JsonObject json = Json.createReader(new StringReader(content)).readObject(); - - //{"f":"DE","t":"092304.01","d":"110813","la":"5117.6370", - // "lo":"01655.3959","a":"00166.6","s":"","c":"","sv":"08","p":"01.6"} - - DateFormat dateFormat = new SimpleDateFormat("ddMMyyHHmmss.SS"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - position.setTime(dateFormat.parse(json.getString("d") + json.getString("t"))); - - String lat = json.getString("la"); - position.setLatitude(Integer.parseInt(lat.substring(0, 2)) + Double.parseDouble(lat.substring(2)) / 60); - String lon = json.getString("lo"); - position.setLongitude(Integer.parseInt(lon.substring(0, 3)) + Double.parseDouble(lon.substring(3)) / 60); - - int flags = Integer.parseInt(json.getString("f")); - position.setValid(BitUtil.check(flags, 1)); - if (!BitUtil.check(flags, 6)) { - position.setLatitude(-position.getLatitude()); - } - if (!BitUtil.check(flags, 7)) { - position.setLongitude(-position.getLongitude()); - } - - position.setAltitude(Double.parseDouble(json.getString("a"))); - position.setSpeed(Double.parseDouble(json.getString("s"))); - position.setCourse(Double.parseDouble(json.getString("c"))); - - position.set(Position.KEY_SATELLITES, Integer.parseInt(json.getString("sv"))); - - return position; - + switch (type) { + case MSG_SEND_EVENTS: + decodeEvents(position, buf); + getLastLocation(position, null); // TODO read timestamp + return position; + case MSG_SEND_TECH_INFO: + decodeTechInfo(position, buf); + getLastLocation(position, null); + return position; + case MSG_SEND_GPS_DATA: + decodeGpsData(position, buf.readSlice(length)); + return position; + case MSG_SEND_CONCATENATED_PACKET: + int count = buf.readUnsignedShortLE(); + for (int i = 0; i < count; i++) { + int partType = buf.readUnsignedShortLE(); + int partLength = buf.readUnsignedShortLE(); + switch (partType) { + case MSG_SEND_EVENTS: + decodeEvents(position, buf); + break; + case MSG_SEND_TECH_INFO: + decodeTechInfo(position, buf); + break; + case MSG_SEND_GPS_DATA: + decodeGpsData(position, buf.readSlice(partLength)); + break; + default: + buf.skipBytes(partLength); + break; + } + } + default: + return null; } - - - return null; } } diff --git a/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java index c334565f9..103f1f48e 100644 --- a/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java @@ -13,8 +13,8 @@ public class SnapperProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "4b0341a6b0c608000040000005000000000000007d5e14010068656c6c6f")); - // data sample - // {"f":"DE","t":"092304.01","d":"110813","la":"5117.6370","lo":"01655.3959","a":"00166.6","s":"","c":"","sv":"08","p":"01.6"} + verifyNull(decoder, binary( + "4b044daff87aff5b8aad00007b010000000013ea0c006837000500210008003e000058c48fa94823001900000080000200018080000002deff0f0003404000000400000034008c007b2273223a22303034303438222c226332223a2230303030303030303030303030303030222c226132223a2230303030303030303030303030303030222c226f223a2230303030222c2274223a2230303030222c227a223a223030222c2277223a223030222c2272223a222d222c226d223a223030303030303030222c2262223a223030303030303030227d320079007b2266223a224445222c2274223a22303932383336222c2264223a22313530343234222c226c61223a22353334312e34333732222c226c6f223a2230303935342e30373036222c2261223a22382e34222c2273223a22302e3030222c2263223a2232362e3036222c227376223a223135222c2270223a22227d33003f007b2263223a22323632222c226e223a223033222c2262223a5b7b226c223a2232423334222c2263223a223030303041313231222c2273223a223132227d5d7d")); } -- cgit v1.2.3