aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/protocol
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar/protocol')
-rw-r--r--src/main/java/org/traccar/protocol/AtrackFrameDecoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java61
-rw-r--r--src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java28
-rw-r--r--src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/FutureWayFrameDecoder.java47
-rw-r--r--src/main/java/org/traccar/protocol/FutureWayProtocol.java38
-rw-r--r--src/main/java/org/traccar/protocol/FutureWayProtocolDecoder.java134
-rw-r--r--src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java103
-rw-r--r--src/main/java/org/traccar/protocol/GlobalSatProtocol.java8
-rw-r--r--src/main/java/org/traccar/protocol/GlobalSatProtocolEncoder.java58
-rw-r--r--src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java15
-rw-r--r--src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java3
-rw-r--r--src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java164
-rw-r--r--src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java3
-rw-r--r--src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java46
-rw-r--r--src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java10
-rw-r--r--src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java60
-rw-r--r--src/main/java/org/traccar/protocol/ItsProtocolDecoder.java8
-rw-r--r--src/main/java/org/traccar/protocol/L100ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java27
-rw-r--r--src/main/java/org/traccar/protocol/MictrackProtocol.java2
-rw-r--r--src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java10
-rw-r--r--src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java47
-rw-r--r--src/main/java/org/traccar/protocol/MoovboxProtocol.java39
-rw-r--r--src/main/java/org/traccar/protocol/MoovboxProtocolDecoder.java106
-rw-r--r--src/main/java/org/traccar/protocol/NetProtocol.java39
-rw-r--r--src/main/java/org/traccar/protocol/NetProtocolDecoder.java92
-rw-r--r--src/main/java/org/traccar/protocol/NiotProtocolDecoder.java58
-rw-r--r--src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java6
-rw-r--r--src/main/java/org/traccar/protocol/PolteProtocol.java39
-rw-r--r--src/main/java/org/traccar/protocol/PolteProtocolDecoder.java84
-rw-r--r--src/main/java/org/traccar/protocol/PstFrameEncoder.java39
-rw-r--r--src/main/java/org/traccar/protocol/PstProtocol.java9
-rw-r--r--src/main/java/org/traccar/protocol/PstProtocolDecoder.java21
-rw-r--r--src/main/java/org/traccar/protocol/PstProtocolEncoder.java62
-rw-r--r--src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java10
-rw-r--r--src/main/java/org/traccar/protocol/RadarProtocolDecoder.java3
-rw-r--r--src/main/java/org/traccar/protocol/SpotProtocolDecoder.java6
-rw-r--r--src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java55
-rw-r--r--src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java65
-rw-r--r--src/main/java/org/traccar/protocol/T55ProtocolDecoder.java48
-rw-r--r--src/main/java/org/traccar/protocol/T800xProtocolDecoder.java8
-rw-r--r--src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java59
-rw-r--r--src/main/java/org/traccar/protocol/V680ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java2
50 files changed, 1474 insertions, 270 deletions
diff --git a/src/main/java/org/traccar/protocol/AtrackFrameDecoder.java b/src/main/java/org/traccar/protocol/AtrackFrameDecoder.java
index f071e2d97..8ed1fc8e8 100644
--- a/src/main/java/org/traccar/protocol/AtrackFrameDecoder.java
+++ b/src/main/java/org/traccar/protocol/AtrackFrameDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2020 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.
@@ -39,7 +39,7 @@ public class AtrackFrameDecoder extends BaseFrameDecoder {
return buf.readRetainedSlice(KEEPALIVE_LENGTH);
}
- } else if (buf.getUnsignedShort(buf.readerIndex()) == 0x4050 && buf.getByte(buf.readerIndex() + 2) != ',') {
+ } else if (buf.getUnsignedByte(buf.readerIndex()) == 0x40 && buf.getByte(buf.readerIndex() + 2) != ',') {
if (buf.readableBytes() > 6) {
int length = buf.getUnsignedShort(buf.readerIndex() + 4) + 4 + 2;
diff --git a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java
index 428b69cd9..56c00c7c1 100644
--- a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2020 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.
@@ -50,10 +50,12 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
private static final int MIN_DATA_LENGTH = 40;
private boolean longDate;
- private boolean decimalFuel;
+ private final boolean decimalFuel;
private boolean custom;
private String form;
+ private ByteBuf photo;
+
private final Map<Integer, String> alarmMap = new HashMap<>();
public AtrackProtocolDecoder(Protocol protocol) {
@@ -510,20 +512,34 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
return position;
}
- private List<Position> decodeBinary(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
+ private Position decodePhoto(DeviceSession deviceSession, ByteBuf buf, long id) {
- buf.skipBytes(2); // prefix
- buf.readUnsignedShort(); // checksum
- buf.readUnsignedShort(); // length
- int index = buf.readUnsignedShort();
+ long time = buf.readUnsignedInt();
+ int index = buf.readUnsignedByte();
+ int count = buf.readUnsignedByte();
- long id = buf.readLong();
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id));
- if (deviceSession == null) {
- return null;
+ if (photo == null) {
+ photo = Unpooled.buffer();
+ }
+ photo.writeBytes(buf.readSlice(buf.readUnsignedShort()));
+
+ if (index == count - 1) {
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, new Date(time * 1000));
+
+ position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(String.valueOf(id), photo, "jpg"));
+ photo.release();
+ photo = null;
+
+ return position;
}
- sendResponse(channel, remoteAddress, id, index);
+ return null;
+ }
+
+ private List<Position> decodeBinary(DeviceSession deviceSession, ByteBuf buf) {
List<Position> positions = new LinkedList<>();
@@ -613,7 +629,26 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
} else if (buf.getByte(buf.readerIndex() + 2) == ',') {
return decodeText(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII).trim());
} else {
- return decodeBinary(channel, remoteAddress, buf);
+
+ String prefix = buf.readCharSequence(2, StandardCharsets.US_ASCII).toString();
+ buf.readUnsignedShort(); // checksum
+ buf.readUnsignedShort(); // length
+ int index = buf.readUnsignedShort();
+
+ long id = buf.readLong();
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id));
+ if (deviceSession == null) {
+ return null;
+ }
+
+ sendResponse(channel, remoteAddress, id, index);
+
+ if (prefix.equals("@R")) {
+ return decodePhoto(deviceSession, buf, id);
+ } else {
+ return decodeBinary(deviceSession, buf);
+ }
+
}
}
diff --git a/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java
index bc74b6576..09bd3572f 100644
--- a/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java
@@ -73,7 +73,7 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder {
content.writeByte(packetNumber);
content.writeZero(11);
- ByteBuf reply = encodeContent(MSG_SERVER_ACKNOWLEDGE, (int) deviceId, packetNumber, content);
+ ByteBuf reply = encodeContent(MSG_SERVER_ACKNOWLEDGE, (int) deviceId, 0, content);
channel.writeAndFlush(new NetworkMessage(reply, remoteAddress));
}
}
diff --git a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java
index d22106a80..115884e2c 100644
--- a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java
@@ -97,7 +97,7 @@ public class EasyTrackProtocolDecoder extends BaseProtocolDecoder {
String sentence = (String) msg;
String type = sentence.substring(20, 22);
- if (type.equals("TX") && channel != null) {
+ if ((type.equals("TX") || type.equals("MQ")) && channel != null) {
channel.writeAndFlush(new NetworkMessage(sentence + "#", remoteAddress));
}
diff --git a/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java
index c3fe7121e..613710587 100644
--- a/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2014 - 2020 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.
@@ -35,6 +35,8 @@ 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;
import java.util.regex.Pattern;
public class EelinkProtocolDecoder extends BaseProtocolDecoder {
@@ -76,6 +78,8 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
case 0x08:
case 0x09:
return Position.ALARM_GPS_ANTENNA_CUT;
+ case 0x25:
+ return Position.ALARM_REMOVING;
case 0x81:
return Position.ALARM_LOW_SPEED;
case 0x82:
@@ -388,9 +392,29 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
deviceSession = getDeviceSession(channel, remoteAddress);
}
+ List<Position> positions = new LinkedList<>();
+
+ while (buf.isReadable()) {
+ Position position = decodePackage(channel, remoteAddress, buf, uniqueId, deviceSession);
+ if (position != null) {
+ positions.add(position);
+ }
+ }
+
+ if (!positions.isEmpty()) {
+ return positions.size() > 1 ? positions : positions.iterator().next();
+ } else {
+ return null;
+ }
+ }
+
+ protected Position decodePackage(
+ Channel channel, SocketAddress remoteAddress, ByteBuf buf,
+ String uniqueId, DeviceSession deviceSession) throws Exception {
+
buf.skipBytes(2); // header
int type = buf.readUnsignedByte();
- buf.readShort(); // length
+ buf = buf.readSlice(buf.readUnsignedShort());
int index = buf.readUnsignedShort();
if (type != MSG_GPS && type != MSG_DATA) {
diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java
index 9bc7cb504..fe42a44d7 100644
--- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java
@@ -60,7 +60,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder {
.number("(-?d+),") // altitude
.number("(d+),") // odometer
.number("d+,") // runtime
- .number("(x{4,8}),") // status
+ .number("(x+),") // status
.number("(x+)?,") // input
.number("(x+)?,") // output
.number("(d+)|") // mcc
diff --git a/src/main/java/org/traccar/protocol/FutureWayFrameDecoder.java b/src/main/java/org/traccar/protocol/FutureWayFrameDecoder.java
new file mode 100644
index 000000000..812f78d02
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/FutureWayFrameDecoder.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import org.traccar.BaseFrameDecoder;
+import org.traccar.helper.DataConverter;
+
+import java.nio.charset.StandardCharsets;
+
+public class FutureWayFrameDecoder extends BaseFrameDecoder {
+
+ @Override
+ protected Object decode(
+ ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception {
+
+ if (buf.readableBytes() < 10) {
+ return null;
+ }
+
+ int length = Unpooled.wrappedBuffer(DataConverter.parseHex(
+ buf.getCharSequence(buf.readerIndex() + 2, 8, StandardCharsets.US_ASCII).toString())).readInt() + 17;
+
+ if (buf.readableBytes() >= length) {
+ return buf.readRetainedSlice(length);
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/FutureWayProtocol.java b/src/main/java/org/traccar/protocol/FutureWayProtocol.java
new file mode 100644
index 000000000..73b53ee12
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/FutureWayProtocol.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+
+public class FutureWayProtocol extends BaseProtocol {
+
+ public FutureWayProtocol() {
+ addServer(new TrackerServer(false, getName()) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ pipeline.addLast(new FutureWayFrameDecoder());
+ pipeline.addLast(new StringEncoder());
+ pipeline.addLast(new StringDecoder());
+ pipeline.addLast(new FutureWayProtocolDecoder(FutureWayProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/FutureWayProtocolDecoder.java b/src/main/java/org/traccar/protocol/FutureWayProtocolDecoder.java
new file mode 100644
index 000000000..4b0f46e34
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/FutureWayProtocolDecoder.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.Protocol;
+import org.traccar.helper.DataConverter;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
+import org.traccar.model.CellTower;
+import org.traccar.model.Network;
+import org.traccar.model.Position;
+import org.traccar.model.WifiAccessPoint;
+
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+public class FutureWayProtocolDecoder extends BaseProtocolDecoder {
+
+ public FutureWayProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN_GPS = new PatternBuilder()
+ .text("GPS:")
+ .expression("([AV]),") // validity
+ .number("(dd)(dd)(dd)") // date (yymmdd)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("(d+.d+)([NS]),") // latitude
+ .number("(d+.d+)([EW]),") // longitude
+ .number("(d+.d+),") // speed
+ .number("(d+.d+)") // course
+ .compile();
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ String sentence = (String) msg;
+
+ ByteBuf header = Unpooled.wrappedBuffer(DataConverter.parseHex(sentence.substring(0, 16)));
+ sentence = sentence.substring(16, sentence.length() - 4);
+
+ header.readUnsignedByte(); // header
+ header.readUnsignedInt(); // length
+ int type = header.readUnsignedByte();
+ header.readUnsignedShort(); // index
+
+ if (type == 0x20) {
+
+ getDeviceSession(channel, remoteAddress, sentence.split(",")[1].substring(5));
+
+ } else if (type == 0xA0) {
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ Network network = new Network();
+
+ for (String line : sentence.split("\r\n")) {
+
+ if (line.startsWith("GPS")) {
+
+ Parser parser = new Parser(PATTERN_GPS, line);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ position.setValid(parser.next().equals("A"));
+ position.setTime(parser.nextDateTime());
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
+
+ } else if (line.startsWith("WIFI")) {
+
+ for (String item : line.substring(line.indexOf(',') + 1).split("&")) {
+ String[] values = item.split("\\|");
+ network.addWifiAccessPoint(
+ WifiAccessPoint.from(values[1].replace('-', ':'), Integer.parseInt(values[2])));
+ }
+
+ } else if (line.startsWith("LBS")) {
+
+ String[] values = line.substring("LBS:".length()).split(",");
+ network.addCellTower(CellTower.from(
+ Integer.parseInt(values[0]),
+ Integer.parseInt(values[1]),
+ Integer.parseInt(values[3]),
+ Integer.parseInt(values[2])));
+
+ }
+
+ }
+
+ if (!network.getCellTowers().isEmpty() || !network.getWifiAccessPoints().isEmpty()) {
+ position.setNetwork(network);
+ }
+
+ if (position.getFixTime() == null) {
+ getLastLocation(position, null);
+ }
+
+ return position;
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java
index 283dbeb37..ec569b71b 100644
--- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2020 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.
@@ -45,7 +45,7 @@ import java.util.regex.Pattern;
public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
- private boolean ignoreFixTime;
+ private final boolean ignoreFixTime;
public Gl200TextProtocolDecoder(Protocol protocol) {
super(protocol);
@@ -190,6 +190,12 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
.expression(PATTERN_LOCATION.pattern())
.expression(")+)")
.groupBegin()
+ .number("d{1,2},,")
+ .number("(d{1,3}),") // battery
+ .number("[01],") // mode
+ .number("(?:[01])?,") // motion
+ .number("(?:-?d{1,2}.d)?,") // temperature
+ .or()
.number("(d{1,7}.d)?,") // odometer
.number("(d{5}:dd:dd)?,") // hour meter
.number("(x+)?,") // adc 1
@@ -226,6 +232,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
.expression("((?:")
.expression(PATTERN_LOCATION.pattern())
.expression(")+)")
+ .groupBegin()
.number("(d{1,7}.d)?,") // odometer
.number("(d{5}:dd:dd)?,") // hour meter
.number("(x+)?,") // adc 1
@@ -233,6 +240,11 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
.number("(d{1,3})?,") // battery
.number("(?:(xx)(xx)(xx))?,") // device status
.expression("(.*)") // additional data
+ .or()
+ .number("d*,,")
+ .number("(d+),") // battery
+ .any()
+ .groupEnd()
.number("(dddd)(dd)(dd)") // date (yyyymmdd)
.number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
.text(",")
@@ -789,8 +801,14 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
} else if (BitUtil.check(ignition, 5)) {
position.set(Position.KEY_IGNITION, true);
}
- position.set(Position.KEY_INPUT, parser.nextHexInt());
- position.set(Position.KEY_OUTPUT, parser.nextHexInt());
+ int input = parser.nextHexInt();
+ int output = parser.nextHexInt();
+ position.set(Position.KEY_INPUT, input);
+ position.set(Position.PREFIX_IN + 1, BitUtil.check(input, 1));
+ position.set(Position.PREFIX_IN + 2, BitUtil.check(input, 2));
+ position.set(Position.KEY_OUTPUT, output);
+ position.set(Position.PREFIX_OUT + 1, BitUtil.check(output, 0));
+ position.set(Position.PREFIX_OUT + 2, BitUtil.check(output, 1));
}
}
@@ -835,6 +853,10 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
}
if (parser.hasNext()) {
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
+ }
+
+ if (parser.hasNext()) {
position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
}
position.set(Position.KEY_HOURS, parseHours(parser.next()));
@@ -897,49 +919,58 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
if (power != null) {
position.set(Position.KEY_POWER, power * 0.001);
}
- position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
- position.set(Position.KEY_HOURS, parseHours(parser.next()));
- position.set(Position.PREFIX_ADC + 1, parser.next());
- position.set(Position.PREFIX_ADC + 2, parser.next());
- position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
- decodeStatus(position, parser);
+ if (parser.hasNext(9)) {
- int index = 0;
- String[] data = parser.next().split(",");
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
+ position.set(Position.KEY_HOURS, parseHours(parser.next()));
+ position.set(Position.PREFIX_ADC + 1, parser.next());
+ position.set(Position.PREFIX_ADC + 2, parser.next());
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
- index += 1; // device type
+ decodeStatus(position, parser);
- if (BitUtil.check(mask, 0)) {
- index += 1; // digital fuel sensor data
- }
+ int index = 0;
+ String[] data = parser.next().split(",");
+
+ index += 1; // device type
+
+ if (BitUtil.check(mask, 0)) {
+ index += 1; // digital fuel sensor data
+ }
- if (BitUtil.check(mask, 1)) {
- int deviceCount = Integer.parseInt(data[index++]);
- for (int i = 1; i <= deviceCount; i++) {
- index += 1; // id
- index += 1; // type
- if (!data[index++].isEmpty()) {
- position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(data[index - 1], 16) * 0.0625);
+ if (BitUtil.check(mask, 1)) {
+ int deviceCount = Integer.parseInt(data[index++]);
+ for (int i = 1; i <= deviceCount; i++) {
+ index += 1; // id
+ index += 1; // type
+ if (!data[index++].isEmpty()) {
+ position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(data[index - 1], 16) * 0.0625);
+ }
}
}
- }
- if (BitUtil.check(mask, 2)) {
- index += 1; // can data
- }
+ if (BitUtil.check(mask, 2)) {
+ index += 1; // can data
+ }
- if (BitUtil.check(mask, 3) || BitUtil.check(mask, 4)) {
- int deviceCount = Integer.parseInt(data[index++]);
- for (int i = 1; i <= deviceCount; i++) {
- index += 1; // type
- if (BitUtil.check(mask, 3)) {
- position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(data[index++]));
- }
- if (BitUtil.check(mask, 4)) {
- index += 1; // volume
+ if (BitUtil.check(mask, 3) || BitUtil.check(mask, 4)) {
+ int deviceCount = Integer.parseInt(data[index++]);
+ for (int i = 1; i <= deviceCount; i++) {
+ index += 1; // type
+ if (BitUtil.check(mask, 3)) {
+ position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(data[index++]));
+ }
+ if (BitUtil.check(mask, 4)) {
+ index += 1; // volume
+ }
}
}
+
+ }
+
+ if (parser.hasNext()) {
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
}
decodeDeviceTime(position, parser);
diff --git a/src/main/java/org/traccar/protocol/GlobalSatProtocol.java b/src/main/java/org/traccar/protocol/GlobalSatProtocol.java
index 7243be72a..e86b5dc30 100644
--- a/src/main/java/org/traccar/protocol/GlobalSatProtocol.java
+++ b/src/main/java/org/traccar/protocol/GlobalSatProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2020 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.
@@ -21,16 +21,22 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.model.Command;
public class GlobalSatProtocol extends BaseProtocol {
public GlobalSatProtocol() {
+ setSupportedDataCommands(
+ Command.TYPE_CUSTOM,
+ Command.TYPE_ALARM_DISMISS,
+ Command.TYPE_OUTPUT_CONTROL);
addServer(new TrackerServer(false, getName()) {
@Override
protected void addProtocolHandlers(PipelineBuilder pipeline) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "!\r\n", "!"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
+ pipeline.addLast(new GlobalSatProtocolEncoder(GlobalSatProtocol.this));
pipeline.addLast(new GlobalSatProtocolDecoder(GlobalSatProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/GlobalSatProtocolEncoder.java b/src/main/java/org/traccar/protocol/GlobalSatProtocolEncoder.java
new file mode 100644
index 000000000..4f56274da
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/GlobalSatProtocolEncoder.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.traccar.Protocol;
+import org.traccar.StringProtocolEncoder;
+import org.traccar.helper.Checksum;
+import org.traccar.model.Command;
+
+public class GlobalSatProtocolEncoder extends StringProtocolEncoder {
+
+ public GlobalSatProtocolEncoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object encodeCommand(Command command) {
+
+ String formattedCommand = null;
+
+ switch (command.getType()) {
+ case Command.TYPE_CUSTOM:
+ formattedCommand = formatCommand(
+ command, "GSC,%s,%s", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
+ break;
+ case Command.TYPE_ALARM_DISMISS:
+ formattedCommand = formatCommand(
+ command, "GSC,%s,Na", Command.KEY_UNIQUE_ID);
+ break;
+ case Command.TYPE_OUTPUT_CONTROL:
+ formattedCommand = formatCommand(
+ command, "GSC,%s,Lo(%s,%s)", Command.KEY_UNIQUE_ID, Command.KEY_INDEX, Command.KEY_DATA);
+ break;
+ default:
+ break;
+ }
+
+ if (formattedCommand != null) {
+ return formattedCommand + Checksum.nmea(formattedCommand) + '!';
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java
index de23ea170..b742d0cac 100644
--- a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java
@@ -60,9 +60,9 @@ import java.util.List;
public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder {
- private DocumentBuilder documentBuilder;
- private XPath xPath;
- private XPathExpression messageExpression;
+ private final DocumentBuilder documentBuilder;
+ private final XPath xPath;
+ private final XPathExpression messageExpression;
public GlobalstarProtocolDecoder(Protocol protocol) {
super(protocol);
@@ -161,17 +161,20 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder {
position.setLongitude(position.getLongitude() - 360);
}
- position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
+ int speed = buf.readUnsignedByte();
+ position.setSpeed(UnitsConverter.knotsFromKph(speed));
position.set("batteryReplace", BitUtil.check(buf.readUnsignedByte(), 7));
- positions.add(position);
+ if (speed != 0xff) {
+ positions.add(position);
+ }
}
}
sendResponse(channel, document.getFirstChild().getAttributes().getNamedItem("messageID").getNodeValue());
- return positions;
+ return !positions.isEmpty() ? positions : null;
}
}
diff --git a/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java
index e00d83061..9b672cacc 100644
--- a/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java
@@ -408,7 +408,7 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
}
}
- if (sentence.substring(21, 21 + 2).equals("vr")) {
+ if (sentence.startsWith("vr", 21)) {
return decodePhoto(channel, remoteAddress, sentence);
} else if (sentence.substring(21, 21 + 3).contains("OBD")) {
return decodeObd(channel, remoteAddress, sentence);
diff --git a/src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java b/src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java
index cc187225b..c158d3212 100644
--- a/src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java
@@ -69,7 +69,8 @@ public class GpsGateProtocolDecoder extends BaseProtocolDecoder {
private void send(Channel channel, SocketAddress remoteAddress, String message) {
if (channel != null) {
- channel.writeAndFlush(new NetworkMessage(message + Checksum.nmea(message) + "\r\n", remoteAddress));
+ channel.writeAndFlush(new NetworkMessage(
+ message + Checksum.nmea(message.substring(1)) + "\r\n", remoteAddress));
}
}
diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java
index 2c2ca7365..e003db51a 100644
--- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java
@@ -59,6 +59,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_LBS = 0x11;
public static final int MSG_GPS_LBS_1 = 0x12;
public static final int MSG_GPS_LBS_2 = 0x22;
+ public static final int MSG_GPS_LBS_3 = 0x37;
public static final int MSG_STATUS = 0x13;
public static final int MSG_SATELLITE = 0x14;
public static final int MSG_STRING = 0x15;
@@ -87,7 +88,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_COMMAND_2 = 0x82;
public static final int MSG_TIME_REQUEST = 0x8A;
public static final int MSG_INFO = 0x94;
- public static final int MSG_RFID = 0x9B;
+ public static final int MSG_SERIAL = 0x9B;
public static final int MSG_STRING_INFO = 0x21;
public static final int MSG_GPS_2 = 0xA0;
public static final int MSG_LBS_2 = 0xA1;
@@ -114,6 +115,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
case MSG_GPS:
case MSG_GPS_LBS_1:
case MSG_GPS_LBS_2:
+ case MSG_GPS_LBS_3:
case MSG_GPS_LBS_STATUS_1:
case MSG_GPS_LBS_STATUS_2:
case MSG_GPS_LBS_STATUS_3:
@@ -134,6 +136,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
case MSG_LBS_STATUS:
case MSG_GPS_LBS_1:
case MSG_GPS_LBS_2:
+ case MSG_GPS_LBS_3:
case MSG_GPS_LBS_STATUS_1:
case MSG_GPS_LBS_STATUS_2:
case MSG_GPS_LBS_STATUS_3:
@@ -736,57 +739,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
} else if (isSupported(type)) {
- if (hasGps(type)) {
- decodeGps(position, buf, false, deviceSession.getTimeZone());
- } else {
- getLastLocation(position, null);
- }
-
- if (hasLbs(type)) {
- decodeLbs(position, buf, hasStatus(type));
- }
-
- if (hasStatus(type)) {
- decodeStatus(position, buf);
- }
-
- if (type == MSG_GPS_LBS_1 && buf.readableBytes() > 75 + 6) {
- position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
- String data = buf.readCharSequence(buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString();
- buf.readUnsignedByte(); // alarm
- buf.readUnsignedByte(); // swiped
- position.set("driverLicense", data.trim());
- }
-
- if (type == MSG_GPS_LBS_1 && buf.readableBytes() == 2 + 6) {
- int mask = buf.readUnsignedShort();
- position.set(Position.KEY_IGNITION, BitUtil.check(mask, 8 + 7));
- position.set(Position.PREFIX_IN + 2, BitUtil.check(mask, 8 + 6));
- if (BitUtil.check(mask, 8 + 4)) {
- int value = BitUtil.to(mask, 8 + 1);
- if (BitUtil.check(mask, 8 + 1)) {
- value = -value;
- }
- position.set(Position.PREFIX_TEMP + 1, value);
- } else {
- int value = BitUtil.to(mask, 8 + 2);
- if (BitUtil.check(mask, 8 + 5)) {
- position.set(Position.PREFIX_ADC + 1, value);
- } else {
- position.set(Position.PREFIX_ADC + 1, value * 0.1);
- }
- }
- }
-
- if (type == MSG_GPS_LBS_2 && buf.readableBytes() == 3 + 6) {
- position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0);
- position.set(Position.KEY_EVENT, buf.readUnsignedByte()); // reason
- position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() > 0);
- }
-
- if (buf.readableBytes() == 4 + 6) {
- position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
- }
+ decodeBasicUniversal(buf, deviceSession, type, position);
} else if (type == MSG_ALARM) {
boolean extendedAlarm = dataLength > 7;
@@ -850,6 +803,80 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private void decodeBasicUniversal(ByteBuf buf, DeviceSession deviceSession, int type, Position position) {
+
+ if (hasGps(type)) {
+ decodeGps(position, buf, false, deviceSession.getTimeZone());
+ } else {
+ getLastLocation(position, null);
+ }
+
+ if (hasLbs(type)) {
+ decodeLbs(position, buf, hasStatus(type));
+ }
+
+ if (hasStatus(type)) {
+ decodeStatus(position, buf);
+ }
+
+ if (type == MSG_GPS_LBS_1 && buf.readableBytes() > 75 + 6) {
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
+ String data = buf.readCharSequence(buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString();
+ buf.readUnsignedByte(); // alarm
+ buf.readUnsignedByte(); // swiped
+ position.set("driverLicense", data.trim());
+ }
+
+ if (type == MSG_GPS_LBS_1 && buf.readableBytes() == 2 + 6) {
+ int mask = buf.readUnsignedShort();
+ position.set(Position.KEY_IGNITION, BitUtil.check(mask, 8 + 7));
+ position.set(Position.PREFIX_IN + 2, BitUtil.check(mask, 8 + 6));
+ if (BitUtil.check(mask, 8 + 4)) {
+ int value = BitUtil.to(mask, 8 + 1);
+ if (BitUtil.check(mask, 8 + 1)) {
+ value = -value;
+ }
+ position.set(Position.PREFIX_TEMP + 1, value);
+ } else {
+ int value = BitUtil.to(mask, 8 + 2);
+ if (BitUtil.check(mask, 8 + 5)) {
+ position.set(Position.PREFIX_ADC + 1, value);
+ } else {
+ position.set(Position.PREFIX_ADC + 1, value * 0.1);
+ }
+ }
+ }
+
+ if ((type == MSG_GPS_LBS_2 || type == MSG_GPS_LBS_3) && buf.readableBytes() >= 3 + 6) {
+ position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0);
+ position.set(Position.KEY_EVENT, buf.readUnsignedByte()); // reason
+ position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() > 0);
+ }
+
+ if (type == MSG_GPS_LBS_3) {
+ int module = buf.readUnsignedShort();
+ int length = buf.readUnsignedByte();
+ switch (module) {
+ case 0x0027:
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
+ break;
+ case 0x002E:
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
+ break;
+ case 0x003B:
+ position.setAccuracy(buf.readUnsignedShort() * 0.01);
+ break;
+ default:
+ buf.skipBytes(length);
+ break;
+ }
+ }
+
+ if (buf.readableBytes() == 4 + 6) {
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
+ }
+ }
+
private Object decodeExtended(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
@@ -1026,18 +1053,6 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return position;
- } else if (type == MSG_RFID) {
-
- getLastLocation(position, null);
-
- buf.readUnsignedByte(); // external device type code
- buf.readUnsignedByte(); // card type
- position.set(
- Position.KEY_DRIVER_UNIQUE_ID,
- buf.readCharSequence(buf.readableBytes() - 9, StandardCharsets.US_ASCII).toString());
-
- return position;
-
} else if (type == MSG_GPS_MODULAR) {
return decodeExtendedModular(buf, deviceSession);
@@ -1205,6 +1220,27 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return position;
+ } else if (type == MSG_SERIAL) {
+
+ position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+ getLastLocation(position, null);
+
+ buf.readUnsignedByte(); // external device type code
+ int length = buf.readableBytes() - 9; // line break + checksum + index + checksum + footer
+ if (length < 8) {
+ position.set(
+ Position.PREFIX_TEMP + 1,
+ Double.parseDouble(buf.readCharSequence(length - 1, StandardCharsets.US_ASCII).toString()));
+ } else {
+ buf.readUnsignedByte(); // card type
+ position.set(
+ Position.KEY_DRIVER_UNIQUE_ID,
+ buf.readCharSequence(length - 1, StandardCharsets.US_ASCII).toString());
+ }
+
+ return position;
+
}
return null;
diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java
index 8d39abead..f1d146bda 100644
--- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java
@@ -190,6 +190,9 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder {
position.set(
Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString());
break;
+ case 0x0011:
+ position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 0.05);
+ break;
case 0x0020:
String[] cells = buf.readCharSequence(
length, StandardCharsets.US_ASCII).toString().split("\\+");
diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
index 841e2235d..b9b156f93 100644
--- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
@@ -57,13 +57,17 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
public static final int RESULT_SUCCESS = 0;
- public static ByteBuf formatMessage(int type, ByteBuf id, ByteBuf data) {
+ public static ByteBuf formatMessage(int type, ByteBuf id, boolean shortIndex, ByteBuf data) {
ByteBuf buf = Unpooled.buffer();
buf.writeByte(0x7e);
buf.writeShort(type);
buf.writeShort(data.readableBytes());
buf.writeBytes(id);
- buf.writeShort(0); // index
+ if (shortIndex) {
+ buf.writeByte(1);
+ } else {
+ buf.writeShort(1);
+ }
buf.writeBytes(data);
data.release();
buf.writeByte(Checksum.xor(buf.nioBuffer(1, buf.readableBytes() - 1)));
@@ -79,18 +83,18 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
response.writeShort(type);
response.writeByte(RESULT_SUCCESS);
channel.writeAndFlush(new NetworkMessage(
- formatMessage(MSG_GENERAL_RESPONSE, id, response), remoteAddress));
+ formatMessage(MSG_GENERAL_RESPONSE, id, false, response), remoteAddress));
}
}
private void sendGeneralResponse2(
- Channel channel, SocketAddress remoteAddress, ByteBuf id, int index) {
+ Channel channel, SocketAddress remoteAddress, ByteBuf id, int type) {
if (channel != null) {
ByteBuf response = Unpooled.buffer();
- response.writeShort(index);
+ response.writeShort(type);
response.writeByte(RESULT_SUCCESS);
channel.writeAndFlush(new NetworkMessage(
- formatMessage(MSG_GENERAL_RESPONSE_2, id, response), remoteAddress));
+ formatMessage(MSG_GENERAL_RESPONSE_2, id, true, response), remoteAddress));
}
}
@@ -161,7 +165,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
response.writeByte(RESULT_SUCCESS);
response.writeBytes(ByteBufUtil.hexDump(id).getBytes(StandardCharsets.US_ASCII));
channel.writeAndFlush(new NetworkMessage(
- formatMessage(MSG_TERMINAL_REGISTER_RESPONSE, id, response), remoteAddress));
+ formatMessage(MSG_TERMINAL_REGISTER_RESPONSE, id, false, response), remoteAddress));
}
} else if (type == MSG_TERMINAL_AUTH) {
@@ -170,12 +174,14 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
} else if (type == MSG_LOCATION_REPORT) {
+ sendGeneralResponse(channel, remoteAddress, id, type, index);
+
return decodeLocation(deviceSession, buf);
} else if (type == MSG_LOCATION_REPORT_2 || type == MSG_LOCATION_REPORT_BLIND) {
if (BitUtil.check(attribute, 15)) {
- sendGeneralResponse2(channel, remoteAddress, id, index);
+ sendGeneralResponse2(channel, remoteAddress, id, type);
}
return decodeLocation2(deviceSession, buf, type);
@@ -296,11 +302,24 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
case 0xD3:
position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1);
break;
+ case 0xD4:
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ break;
+ case 0xD5:
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
+ break;
+ case 0xDA:
+ buf.readUnsignedShort(); // string cut count
+ int deviceStatus = buf.readUnsignedByte();
+ position.set("string", BitUtil.check(deviceStatus, 0));
+ position.set(Position.KEY_MOTION, BitUtil.check(deviceStatus, 2));
+ position.set("cover", BitUtil.check(deviceStatus, 3));
+ break;
case 0xEB:
while (buf.readerIndex() < endIndex) {
- int tenetLength = buf.readUnsignedShort();
- int tenetType = buf.readUnsignedShort();
- switch (tenetType) {
+ int extendedLength = buf.readUnsignedShort();
+ int extendedType = buf.readUnsignedShort();
+ switch (extendedType) {
case 0x0001:
position.set("fuel1", buf.readUnsignedShort() * 0.1);
buf.readUnsignedByte(); // unused
@@ -309,8 +328,11 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set("fuel2", Double.parseDouble(
buf.readCharSequence(6, StandardCharsets.US_ASCII).toString()));
break;
+ case 0x00CE:
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
+ break;
default:
- buf.skipBytes(tenetLength - 2);
+ buf.skipBytes(extendedLength - 2);
break;
}
}
diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java
index 40d07230d..55c1e0c3b 100644
--- a/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2020 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.
@@ -50,22 +50,22 @@ public class HuabaoProtocolEncoder extends BaseProtocolEncoder {
data.writeByte(0x01);
data.writeBytes(time);
return HuabaoProtocolDecoder.formatMessage(
- HuabaoProtocolDecoder.MSG_OIL_CONTROL, id, data);
+ HuabaoProtocolDecoder.MSG_OIL_CONTROL, id, false, data);
} else {
data.writeByte(0xf0);
return HuabaoProtocolDecoder.formatMessage(
- HuabaoProtocolDecoder.MSG_TERMINAL_CONTROL, id, data);
+ HuabaoProtocolDecoder.MSG_TERMINAL_CONTROL, id, false, data);
}
case Command.TYPE_ENGINE_RESUME:
if (alternative) {
data.writeByte(0x00);
data.writeBytes(time);
return HuabaoProtocolDecoder.formatMessage(
- HuabaoProtocolDecoder.MSG_OIL_CONTROL, id, data);
+ HuabaoProtocolDecoder.MSG_OIL_CONTROL, id, false, data);
} else {
data.writeByte(0xf1);
return HuabaoProtocolDecoder.formatMessage(
- HuabaoProtocolDecoder.MSG_TERMINAL_CONTROL, id, data);
+ HuabaoProtocolDecoder.MSG_TERMINAL_CONTROL, id, false, data);
}
default:
return null;
diff --git a/src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java b/src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java
index 897606270..930d4f23b 100644
--- a/src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2020 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.
@@ -44,7 +44,7 @@ public class IntellitracProtocolDecoder extends BaseProtocolDecoder {
.number("(d+.?d*),") // course
.number("(-?d+.?d*),") // altitude
.number("(d+),") // satellites
- .number("(d+),") // index
+ .number("(d+),") // event
.number("(d+),") // input
.number("(d+),?") // output
.number("(d+.d+)?,?") // adc1
@@ -65,6 +65,30 @@ public class IntellitracProtocolDecoder extends BaseProtocolDecoder {
.any()
.compile();
+ private String decodeAlarm(int value) {
+ switch (value) {
+ case 164:
+ return Position.ALARM_GEOFENCE_ENTER;
+ case 165:
+ return Position.ALARM_GEOFENCE_EXIT;
+ case 168:
+ case 169:
+ return Position.ALARM_LOW_POWER;
+ case 170:
+ return Position.ALARM_POWER_OFF;
+ case 176:
+ return Position.ALARM_POWER_RESTORED;
+ case 180:
+ return Position.ALARM_FALL_DOWN;
+ case 225:
+ return Position.ALARM_JAMMING;
+ case 995:
+ return Position.ALARM_SOS;
+ default:
+ return null;
+ }
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -74,12 +98,12 @@ public class IntellitracProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- Position position = new Position(getProtocolName());
-
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
if (deviceSession == null) {
return null;
}
+
+ Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
position.setTime(parser.nextDateTime());
@@ -92,7 +116,11 @@ public class IntellitracProtocolDecoder extends BaseProtocolDecoder {
position.setAltitude(parser.nextDouble());
position.set(Position.KEY_SATELLITES, parser.nextInt());
- position.set(Position.KEY_INDEX, parser.nextLong());
+
+ int event = parser.nextInt();
+ position.set(Position.KEY_ALARM, decodeAlarm(event));
+ position.set(Position.KEY_EVENT, event);
+
position.set(Position.KEY_INPUT, parser.nextInt());
position.set(Position.KEY_OUTPUT, parser.nextInt());
@@ -100,16 +128,18 @@ public class IntellitracProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.PREFIX_ADC + 2, parser.nextDouble());
// J1939 data
- position.set(Position.KEY_OBD_SPEED, parser.nextInt());
- position.set(Position.KEY_RPM, parser.nextInt());
- position.set("coolant", parser.nextInt());
- position.set(Position.KEY_FUEL_LEVEL, parser.nextInt());
- position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextInt());
- position.set(Position.PREFIX_TEMP + 1, parser.nextInt());
- position.set("chargerPressure", parser.nextInt());
- position.set("tpl", parser.nextInt());
- position.set(Position.KEY_AXLE_WEIGHT, parser.nextInt());
- position.set(Position.KEY_OBD_ODOMETER, parser.nextInt());
+ if (parser.hasNext(10)) {
+ position.set(Position.KEY_OBD_SPEED, parser.nextInt());
+ position.set(Position.KEY_RPM, parser.nextInt());
+ position.set("coolant", parser.nextInt());
+ position.set(Position.KEY_FUEL_LEVEL, parser.nextInt());
+ position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextInt());
+ position.set(Position.PREFIX_TEMP + 1, parser.nextInt());
+ position.set("chargerPressure", parser.nextInt());
+ position.set("tpl", parser.nextInt());
+ position.set(Position.KEY_AXLE_WEIGHT, parser.nextInt());
+ position.set(Position.KEY_OBD_ODOMETER, parser.nextInt());
+ }
return position;
}
diff --git a/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java b/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java
index f66669a98..94c9a3038 100644
--- a/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java
@@ -90,6 +90,10 @@ public class ItsProtocolDecoder extends BaseProtocolDecoder {
.number("(-?d+),") // tilt x
.or()
.number("d+,") // index
+ .number("(d+.?d*),") // odometer
+ .number("x+,") // checksum
+ .or()
+ .number("d+,") // index
.number("(d+.?d*),") // adc1
.number("(d+.?d*),") // adc2
.groupEnd("?")
@@ -244,6 +248,10 @@ public class ItsProtocolDecoder extends BaseProtocolDecoder {
position.set("tiltX", parser.nextInt());
}
+ if (parser.hasNext()) {
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
+ }
+
if (parser.hasNext(2)) {
position.set(Position.PREFIX_ADC + 1, parser.nextDouble());
position.set(Position.PREFIX_ADC + 2, parser.nextDouble());
diff --git a/src/main/java/org/traccar/protocol/L100ProtocolDecoder.java b/src/main/java/org/traccar/protocol/L100ProtocolDecoder.java
index 9868de435..5b5eb7d60 100644
--- a/src/main/java/org/traccar/protocol/L100ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/L100ProtocolDecoder.java
@@ -138,7 +138,7 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
String sentence = (String) msg;
if (sentence.startsWith("L") || sentence.startsWith("H")) {
- if (sentence.substring(2, 8).equals("ATLOBD")) {
+ if (sentence.startsWith("ATLOBD", 2)) {
return decodeObdData(channel, remoteAddress, sentence);
} else {
return decodeObdLocation(channel, remoteAddress, sentence);
diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java
index 0c72568f3..4abb75025 100644
--- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java
@@ -152,7 +152,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder {
if (responseCode != null) {
String response = "$AVCFG," + devicePassword + "," + responseCode;
- response += Checksum.nmea(response) + "\r\n";
+ response += Checksum.nmea(response.substring(1)) + "\r\n";
channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
}
@@ -163,7 +163,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder {
if (Character.isLowerCase(status.charAt(0))) {
String response = "$EAVACK," + event + "," + checksum;
- response += Checksum.nmea(response) + "\r\n";
+ response += Checksum.nmea(response.substring(1)) + "\r\n";
channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
}
diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java
index 0c9f8ebb8..aaa5a70f7 100644
--- a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java
@@ -29,7 +29,7 @@ public class LaipacProtocolEncoder extends StringProtocolEncoder {
@Override
protected String formatCommand(Command command, String format, String... keys) {
String sentence = super.formatCommand(command, "$" + format, keys);
- sentence += Checksum.nmea(sentence) + "\r\n";
+ sentence += Checksum.nmea(sentence.substring(1)) + "\r\n";
return sentence;
}
diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java
index 529496928..c43f1ea83 100644
--- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java
@@ -177,8 +177,8 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
position.setNetwork(new Network(CellTower.from(
parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt(), rssi)));
- position.set(Position.KEY_OUTPUT, parser.nextHexInt());
position.set(Position.KEY_INPUT, parser.nextHexInt());
+ position.set(Position.KEY_OUTPUT, parser.nextHexInt());
for (int i = 1; i <= 3; i++) {
position.set(Position.PREFIX_ADC + i, parser.nextHexInt());
@@ -421,6 +421,22 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
case 0x1A:
position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.01);
break;
+ case 0x91:
+ case 0x92:
+ position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShortLE());
+ break;
+ case 0x98:
+ position.set(Position.KEY_FUEL_USED, buf.readUnsignedShortLE());
+ break;
+ case 0x99:
+ position.set(Position.KEY_RPM, buf.readUnsignedShortLE());
+ break;
+ case 0x9C:
+ position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedShortLE());
+ break;
+ case 0xC9:
+ position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShortLE());
+ break;
default:
buf.readUnsignedShortLE();
break;
@@ -440,9 +456,18 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
case 0x04:
position.setTime(new Date((946684800 + buf.readUnsignedIntLE()) * 1000)); // 2000-01-01
break;
+ case 0x0C:
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE());
+ break;
case 0x0D:
position.set("runtime", buf.readUnsignedIntLE());
break;
+ case 0xA0:
+ position.set(Position.KEY_FUEL_USED, buf.readUnsignedIntLE() * 0.001);
+ break;
+ case 0xA2:
+ position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedIntLE() * 0.01);
+ break;
default:
buf.readUnsignedIntLE();
break;
diff --git a/src/main/java/org/traccar/protocol/MictrackProtocol.java b/src/main/java/org/traccar/protocol/MictrackProtocol.java
index c8d64fd81..9fd9666e4 100644
--- a/src/main/java/org/traccar/protocol/MictrackProtocol.java
+++ b/src/main/java/org/traccar/protocol/MictrackProtocol.java
@@ -15,7 +15,6 @@
*/
package org.traccar.protocol;
-import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
@@ -28,7 +27,6 @@ public class MictrackProtocol extends BaseProtocol {
addServer(new TrackerServer(false, getName()) {
@Override
protected void addProtocolHandlers(PipelineBuilder pipeline) {
- pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new MictrackProtocolDecoder(MictrackProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java
index 0f815ca7b..5ea9f148c 100644
--- a/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java
@@ -66,6 +66,8 @@ public class MictrackProtocolDecoder extends BaseProtocolDecoder {
private String decodeAlarm(int event) {
switch (event) {
+ case 0:
+ return Position.ALARM_POWER_ON;
case 5:
return Position.ALARM_SOS;
case 8:
@@ -209,8 +211,12 @@ public class MictrackProtocolDecoder extends BaseProtocolDecoder {
}
private Object decodeLowAltitude(
- Channel channel, SocketAddress remoteAddress, String sentence) throws Exception {
- String deviceId = sentence.substring(0, sentence.indexOf("$"));
+ Channel channel, SocketAddress remoteAddress, String sentence) {
+ int separator = sentence.indexOf("$");
+ if (separator < 0) {
+ return null;
+ }
+ String deviceId = sentence.substring(0, separator);
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, deviceId);
if (deviceSession == null) {
diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
index b8ab134c5..5b04992ec 100644
--- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2019 - 2020 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.
@@ -34,6 +34,10 @@ import org.traccar.model.WifiAccessPoint;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
@@ -100,18 +104,33 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
if (type == MSG_DATA) {
+ List<Position> positions = new LinkedList<>();
+ Set<Integer> keys = new HashSet<>();
+ boolean hasLocation = false;
Position position = new Position(getProtocolName());
+ DeviceSession deviceSession = null;
+
while (buf.isReadable()) {
int endIndex = buf.readUnsignedByte() + buf.readerIndex();
int key = buf.readUnsignedByte();
+
+ if (keys.contains(key)) {
+ if (!hasLocation) {
+ getLastLocation(position, null);
+ }
+ positions.add(position);
+ keys.clear();
+ hasLocation = false;
+ position = new Position(getProtocolName());
+ }
+ keys.add(key);
+
switch (key) {
case 0x01:
- DeviceSession deviceSession = getDeviceSession(
+ deviceSession = getDeviceSession(
channel, remoteAddress, buf.readCharSequence(15, StandardCharsets.US_ASCII).toString());
- if (deviceSession == null) {
- return null;
- }
+
position.setDeviceId(deviceSession.getDeviceId());
break;
case 0x02:
@@ -122,6 +141,7 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001);
break;
case 0x20:
+ hasLocation = true;
position.setLatitude(buf.readIntLE() * 0.0000001);
position.setLongitude(buf.readIntLE() * 0.0000001);
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE()));
@@ -169,6 +189,10 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_BATTERY_LEVEL, BitUtil.from(status, 24));
position.set(Position.KEY_STATUS, status);
break;
+ case 0x30:
+ buf.readUnsignedInt(); // timestamp
+ position.set(Position.KEY_STEPS, buf.readUnsignedInt());
+ break;
case 0x40:
buf.readUnsignedIntLE(); // timestamp
int heartRate = buf.readUnsignedByte();
@@ -182,11 +206,20 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
buf.readerIndex(endIndex);
}
- if (!position.getAttributes().containsKey(Position.KEY_SATELLITES)) {
+ if (!hasLocation) {
getLastLocation(position, null);
}
+ positions.add(position);
+
+ if (deviceSession != null) {
+ for (Position p : positions) {
+ p.setDeviceId(deviceSession.getDeviceId());
+ }
+ } else {
+ return null;
+ }
- return position.getDeviceId() > 0 ? position : null;
+ return positions;
}
diff --git a/src/main/java/org/traccar/protocol/MoovboxProtocol.java b/src/main/java/org/traccar/protocol/MoovboxProtocol.java
new file mode 100644
index 000000000..7b554266f
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/MoovboxProtocol.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+
+public class MoovboxProtocol extends BaseProtocol {
+
+ public MoovboxProtocol() {
+ addServer(new TrackerServer(false, getName()) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ pipeline.addLast(new HttpResponseEncoder());
+ pipeline.addLast(new HttpRequestDecoder());
+ pipeline.addLast(new HttpObjectAggregator(65535));
+ pipeline.addLast(new MoovboxProtocolDecoder(MoovboxProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/MoovboxProtocolDecoder.java b/src/main/java/org/traccar/protocol/MoovboxProtocolDecoder.java
new file mode 100644
index 000000000..3116d073c
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/MoovboxProtocolDecoder.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import com.fasterxml.jackson.databind.util.ByteBufferBackedInputStream;
+import io.netty.channel.Channel;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import org.traccar.BaseHttpProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.Protocol;
+import org.traccar.model.Position;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import java.net.SocketAddress;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+public class MoovboxProtocolDecoder extends BaseHttpProtocolDecoder {
+
+ private final DocumentBuilder documentBuilder;
+ private final XPath xPath;
+ private final XPathExpression messageExpression;
+
+ public MoovboxProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ try {
+ DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+ builderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ builderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
+ builderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ builderFactory.setXIncludeAware(false);
+ builderFactory.setExpandEntityReferences(false);
+ documentBuilder = builderFactory.newDocumentBuilder();
+ xPath = XPathFactory.newInstance().newXPath();
+ messageExpression = xPath.compile("//gps/coordinates/coordinate");
+ } catch (ParserConfigurationException | XPathExpressionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ FullHttpRequest request = (FullHttpRequest) msg;
+
+ Document document = documentBuilder.parse(new ByteBufferBackedInputStream(request.content().nioBuffer()));
+
+ String id = document.getDocumentElement().getAttribute("id");
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ NodeList nodes = (NodeList) messageExpression.evaluate(document, XPathConstants.NODESET);
+ List<Position> positions = new LinkedList<>();
+
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node node = nodes.item(i);
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setValid(true);
+ position.setTime(new Date(Long.parseLong(xPath.evaluate("time", node)) * 1000));
+ position.setLatitude(Double.parseDouble(xPath.evaluate("longitude", node)));
+ position.setLongitude(Double.parseDouble(xPath.evaluate("latitude", node)));
+ position.setAltitude(Double.parseDouble(xPath.evaluate("altitude", node)));
+ position.setSpeed(Double.parseDouble(xPath.evaluate("speed", node)));
+
+ position.set(Position.KEY_SATELLITES, Integer.parseInt(xPath.evaluate("satellites", node)));
+
+ positions.add(position);
+ }
+
+ sendResponse(channel, HttpResponseStatus.OK);
+ return positions;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/NetProtocol.java b/src/main/java/org/traccar/protocol/NetProtocol.java
new file mode 100644
index 000000000..c114d19fc
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/NetProtocol.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.CharacterDelimiterFrameDecoder;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+
+public class NetProtocol extends BaseProtocol {
+
+ public NetProtocol() {
+ addServer(new TrackerServer(false, getName()) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '!'));
+ pipeline.addLast(new StringEncoder());
+ pipeline.addLast(new StringDecoder());
+ pipeline.addLast(new NetProtocolDecoder(NetProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/NetProtocolDecoder.java b/src/main/java/org/traccar/protocol/NetProtocolDecoder.java
new file mode 100644
index 000000000..61cb29b6b
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/NetProtocolDecoder.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+public class NetProtocolDecoder extends BaseProtocolDecoder {
+
+ public NetProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("@L")
+ .number("ddd")
+ .number("(d{15})") // imei
+ .number("xx")
+ .number("(dd)(dd)(dd)") // date (ddmmyy)
+ .number("(dd)(dd)(dd)") // time (hhmmss)
+ .number("(x)") // flags
+ .number("(dd)(dd)(dddd)") // latitude
+ .number("(ddd)(dd)(dddd)") // longitude
+ .number("(x{8})") // status
+ .number("(x{4})") // speed
+ .number("(x{6})") // odometer
+ .number("(xxx)") // course
+ .number("(xxx)") // alarm
+ .any()
+ .compile();
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ Parser parser = new Parser(PATTERN, (String) msg);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+
+ int flags = parser.nextHexInt();
+
+ position.setValid(BitUtil.check(flags, 3));
+ int hemisphereLatitude = BitUtil.check(flags, 1) ? -1 : 1;
+ int hemisphereLongitude = BitUtil.check(flags, 0) ? -1 : 1;
+
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN) * hemisphereLatitude);
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN) * hemisphereLongitude);
+
+ position.set(Position.KEY_STATUS, parser.nextHexLong());
+ position.setSpeed(parser.nextHexInt() * 0.01);
+ position.set(Position.KEY_ODOMETER, parser.nextHexInt());
+ position.setCourse(parser.nextHexInt());
+
+ parser.nextHexInt(); // alarm
+
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/NiotProtocolDecoder.java b/src/main/java/org/traccar/protocol/NiotProtocolDecoder.java
index 58de0d38f..47c6e2ffd 100644
--- a/src/main/java/org/traccar/protocol/NiotProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/NiotProtocolDecoder.java
@@ -31,6 +31,7 @@ import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
public class NiotProtocolDecoder extends BaseProtocolDecoder {
@@ -95,12 +96,65 @@ public class NiotProtocolDecoder extends BaseProtocolDecoder {
.setSecond(BcdUtil.readInteger(buf, 2));
position.setTime(dateBuilder.getDate());
- position.setValid(true);
position.setLatitude(readCoordinate(buf));
position.setLongitude(readCoordinate(buf));
- position.setSpeed(UnitsConverter.knotsFromKph(BcdUtil.readInteger(buf, 4)));
+ BcdUtil.readInteger(buf, 4); // reserved
position.setCourse(BcdUtil.readInteger(buf, 4));
+ int statusX = buf.readUnsignedByte();
+ position.setValid(BitUtil.check(statusX, 7));
+ switch (BitUtil.between(statusX, 3, 5)) {
+ case 0b10:
+ position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT);
+ break;
+ case 0b01:
+ position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER);
+ break;
+ default:
+ break;
+ }
+
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
+
+ int statusA = buf.readUnsignedByte();
+ position.set(Position.KEY_IGNITION, !BitUtil.check(statusA, 7));
+ if (!BitUtil.check(statusA, 6)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED);
+ }
+
+ buf.readUnsignedByte(); // statusB
+ buf.readUnsignedByte(); // statusC
+ position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.1);
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1);
+ buf.readUnsignedByte(); // speed limit
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
+ buf.readUnsignedByte(); // sensor speed
+ buf.readUnsignedByte(); // reserved
+ buf.readUnsignedByte(); // reserved
+
+ while (buf.readableBytes() > 4) {
+ int extendedLength = buf.readUnsignedShort();
+ int extendedType = buf.readUnsignedShort();
+ switch (extendedType) {
+ case 0x0001:
+ position.set(Position.KEY_ICCID,
+ buf.readCharSequence(20, StandardCharsets.US_ASCII).toString());
+ break;
+ case 0x0002:
+ int statusD = buf.readUnsignedByte();
+ position.set(Position.KEY_ALARM, BitUtil.check(statusD, 5) ? Position.ALARM_REMOVING : null);
+ position.set(Position.KEY_ALARM, BitUtil.check(statusD, 4) ? Position.ALARM_TAMPERING : null);
+ buf.readUnsignedByte(); // run mode
+ buf.readUnsignedByte(); // reserved
+ break;
+ default:
+ buf.skipBytes(extendedLength - 2);
+ break;
+ }
+
+ }
+
return position;
}
diff --git a/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java b/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java
index 323d97fa3..509d14ae4 100644
--- a/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java
@@ -110,7 +110,7 @@ public class OwnTracksProtocolDecoder extends BaseHttpProtocolDecoder {
if (root.containsKey("t")) {
String trigger = root.getString("t");
position.set("t", trigger);
- Integer reportType = -1;
+ int reportType = -1;
if (root.containsKey("rty")) {
reportType = root.getInt("rty");
}
@@ -148,8 +148,8 @@ public class OwnTracksProtocolDecoder extends BaseHttpProtocolDecoder {
}
if (root.containsKey("anum")) {
- Integer numberOfAnalogueInputs = root.getInt("anum");
- for (Integer i = 0; i < numberOfAnalogueInputs; i++) {
+ int numberOfAnalogueInputs = root.getInt("anum");
+ for (int i = 0; i < numberOfAnalogueInputs; i++) {
String indexString = String.format("%02d", i);
if (root.containsKey("adda-" + indexString)) {
position.set(Position.PREFIX_ADC + (i + 1), root.getString("adda-" + indexString));
diff --git a/src/main/java/org/traccar/protocol/PolteProtocol.java b/src/main/java/org/traccar/protocol/PolteProtocol.java
new file mode 100644
index 000000000..a3e548716
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/PolteProtocol.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+
+public class PolteProtocol extends BaseProtocol {
+
+ public PolteProtocol() {
+ addServer(new TrackerServer(false, getName()) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ pipeline.addLast(new HttpResponseEncoder());
+ pipeline.addLast(new HttpRequestDecoder());
+ pipeline.addLast(new HttpObjectAggregator(65535));
+ pipeline.addLast(new PolteProtocolDecoder(PolteProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java b/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java
new file mode 100644
index 000000000..ce45abef6
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.channel.Channel;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import org.traccar.BaseHttpProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.Protocol;
+import org.traccar.model.Position;
+
+import javax.json.Json;
+import javax.json.JsonObject;
+import java.io.StringReader;
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+
+public class PolteProtocolDecoder extends BaseHttpProtocolDecoder {
+
+ public PolteProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ FullHttpRequest request = (FullHttpRequest) msg;
+ String content = request.content().toString(StandardCharsets.UTF_8);
+ JsonObject json = Json.createReader(new StringReader(content)).readObject();
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, json.getString("ueToken"));
+ if (deviceSession == null) {
+ sendResponse(channel, HttpResponseStatus.BAD_REQUEST);
+ return null;
+ }
+
+ if (json.containsKey("location")) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ JsonObject location = json.getJsonObject("location");
+
+ position.setValid(true);
+ position.setTime(new Date(location.getInt("detected_at") * 1000L));
+ position.setLatitude(location.getJsonNumber("latitude").doubleValue());
+ position.setLongitude(location.getJsonNumber("longitude").doubleValue());
+ position.setAltitude(location.getJsonNumber("altitude").doubleValue());
+
+ if (json.containsKey("report")) {
+ JsonObject report = json.getJsonObject("report");
+ position.set(Position.KEY_EVENT, report.getInt("event"));
+ if (report.containsKey("battery")) {
+ JsonObject battery = report.getJsonObject("battery");
+ position.set(Position.KEY_BATTERY_LEVEL, battery.getInt("level"));
+ position.set(Position.KEY_BATTERY, battery.getJsonNumber("voltage").doubleValue());
+ }
+ }
+
+ return position;
+
+ }
+
+ sendResponse(channel, HttpResponseStatus.OK);
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/PstFrameEncoder.java b/src/main/java/org/traccar/protocol/PstFrameEncoder.java
new file mode 100644
index 000000000..5a9ede3e6
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/PstFrameEncoder.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToByteEncoder;
+
+public class PstFrameEncoder extends MessageToByteEncoder<ByteBuf> {
+
+ @Override
+ protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) {
+
+ out.writeByte('(');
+ while (msg.isReadable()) {
+ int b = msg.readUnsignedByte();
+ if (b == 0x27 || b == 0x28 || b == 0x29) {
+ out.writeByte(0x27);
+ out.writeByte(b ^ 0x40);
+ } else {
+ out.writeByte(b);
+ }
+ }
+ out.writeByte(')');
+ }
+}
diff --git a/src/main/java/org/traccar/protocol/PstProtocol.java b/src/main/java/org/traccar/protocol/PstProtocol.java
index 0ed9affd8..d8c7008cb 100644
--- a/src/main/java/org/traccar/protocol/PstProtocol.java
+++ b/src/main/java/org/traccar/protocol/PstProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2019 - 2020 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.
@@ -18,20 +18,27 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.model.Command;
public class PstProtocol extends BaseProtocol {
public PstProtocol() {
+ setSupportedDataCommands(
+ Command.TYPE_ENGINE_STOP,
+ Command.TYPE_ENGINE_RESUME);
addServer(new TrackerServer(true, getName()) {
@Override
protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ pipeline.addLast(new PstProtocolEncoder(PstProtocol.this));
pipeline.addLast(new PstProtocolDecoder(PstProtocol.this));
}
});
addServer(new TrackerServer(false, getName()) {
@Override
protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ pipeline.addLast(new PstFrameEncoder());
pipeline.addLast(new PstFrameDecoder());
+ pipeline.addLast(new PstProtocolEncoder(PstProtocol.this));
pipeline.addLast(new PstProtocolDecoder(PstProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/PstProtocolDecoder.java b/src/main/java/org/traccar/protocol/PstProtocolDecoder.java
index 62cc203d2..e3fe1af62 100644
--- a/src/main/java/org/traccar/protocol/PstProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PstProtocolDecoder.java
@@ -38,6 +38,7 @@ public class PstProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_ACK = 0x00;
public static final int MSG_STATUS = 0x05;
+ public static final int MSG_COMMAND = 0x06;
private Date readDate(ByteBuf buf) {
long value = buf.readUnsignedInt();
@@ -61,21 +62,13 @@ public class PstProtocolDecoder extends BaseProtocolDecoder {
Channel channel, SocketAddress remoteAddress, long id, int version, long index, int type) {
if (channel != null) {
- ByteBuf content = Unpooled.buffer();
- content.writeInt((int) id);
- content.writeByte(version);
- content.writeInt((int) index);
- content.writeByte(MSG_ACK);
- content.writeByte(type);
-
- int checksum = Checksum.crc16(Checksum.CRC16_XMODEM, content.nioBuffer());
-
ByteBuf response = Unpooled.buffer();
- response.writeByte('(');
- response.writeBytes(content);
- content.release();
- response.writeShort(checksum);
- response.writeByte(')');
+ response.writeInt((int) id);
+ response.writeByte(version);
+ response.writeInt((int) index);
+ response.writeByte(MSG_ACK);
+ response.writeByte(type);
+ response.writeShort(Checksum.crc16(Checksum.CRC16_XMODEM, response.nioBuffer()));
channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
diff --git a/src/main/java/org/traccar/protocol/PstProtocolEncoder.java b/src/main/java/org/traccar/protocol/PstProtocolEncoder.java
new file mode 100644
index 000000000..f3d193324
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/PstProtocolEncoder.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.traccar.BaseProtocolEncoder;
+import org.traccar.Protocol;
+import org.traccar.helper.Checksum;
+import org.traccar.model.Command;
+
+public class PstProtocolEncoder extends BaseProtocolEncoder {
+
+ public PstProtocolEncoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private ByteBuf encodeContent(long deviceId, int type, int data1, int data2) {
+
+ ByteBuf buf = Unpooled.buffer();
+
+ buf.writeInt((int) Long.parseLong(getUniqueId(deviceId)));
+ buf.writeByte(0x06); // version
+
+ buf.writeInt(1); // index
+ buf.writeByte(PstProtocolDecoder.MSG_COMMAND);
+ buf.writeShort(type);
+ buf.writeShort(data1);
+ buf.writeShort(data2);
+
+ buf.writeShort(Checksum.crc16(Checksum.CRC16_XMODEM, buf.nioBuffer()));
+
+ return buf;
+ }
+
+ @Override
+ protected Object encodeCommand(Command command) {
+
+ switch (command.getType()) {
+ case Command.TYPE_ENGINE_STOP:
+ return encodeContent(command.getDeviceId(), 0x0002, 0xffff, 0xffff);
+ case Command.TYPE_ENGINE_RESUME:
+ return encodeContent(command.getDeviceId(), 0x0001, 0xffff, 0xffff);
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java
index 0afec67ad..ff92b51f1 100644
--- a/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2020 Anton Tananaev (anton@traccar.org)
* Copyright 2012 Luis Parada (luis.parada@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -55,8 +55,8 @@ public class Pt502ProtocolDecoder extends BaseProtocolDecoder {
.expression("([EW]),")
.number("(d+.d+)?,") // speed
.number("(d+.d+)?,") // course
- .number("(dd)(dd)(dd),,,") // date (ddmmyy)
- .expression("./")
+ .number("(dd)(dd)(dd),,,?") // date (ddmmyy)
+ .expression(".?/")
.expression("([01])+,") // input
.expression("([01])+/") // output
.expression("([^/]+)?/") // adc
@@ -108,7 +108,7 @@ public class Pt502ProtocolDecoder extends BaseProtocolDecoder {
position.setDeviceId(deviceSession.getDeviceId());
DateBuilder dateBuilder = new DateBuilder()
- .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt());
position.setValid(parser.next().equals("A"));
position.setLatitude(parser.nextCoordinate());
@@ -116,7 +116,7 @@ public class Pt502ProtocolDecoder extends BaseProtocolDecoder {
position.setSpeed(parser.nextDouble(0));
position.setCourse(parser.nextDouble(0));
- dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
+ dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
position.setTime(dateBuilder.getDate());
position.set(Position.KEY_INPUT, parser.next());
diff --git a/src/main/java/org/traccar/protocol/RadarProtocolDecoder.java b/src/main/java/org/traccar/protocol/RadarProtocolDecoder.java
index b56a081c7..d87f77b84 100644
--- a/src/main/java/org/traccar/protocol/RadarProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/RadarProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2019 - 2020 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.
@@ -70,6 +70,7 @@ public class RadarProtocolDecoder extends BaseProtocolDecoder {
for (int index = 0; index < count; index++) {
Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
position.set(Position.KEY_EVENT, buf.readUnsignedShort());
diff --git a/src/main/java/org/traccar/protocol/SpotProtocolDecoder.java b/src/main/java/org/traccar/protocol/SpotProtocolDecoder.java
index da36c2048..34417d95f 100644
--- a/src/main/java/org/traccar/protocol/SpotProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SpotProtocolDecoder.java
@@ -42,9 +42,9 @@ import java.util.List;
public class SpotProtocolDecoder extends BaseHttpProtocolDecoder {
- private DocumentBuilder documentBuilder;
- private XPath xPath;
- private XPathExpression messageExpression;
+ private final DocumentBuilder documentBuilder;
+ private final XPath xPath;
+ private final XPathExpression messageExpression;
public SpotProtocolDecoder(Protocol protocol) {
super(protocol);
diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java
index 2d1613e03..7ba41ad56 100644
--- a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java
@@ -20,11 +20,13 @@ import org.traccar.BaseProtocolDecoder;
import org.traccar.Context;
import org.traccar.DeviceSession;
import org.traccar.Protocol;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
import org.traccar.model.Position;
+import org.traccar.protobuf.StarLinkMessage;
import java.net.SocketAddress;
import java.text.DateFormat;
@@ -47,8 +49,8 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder {
.number("xx") // checksum
.compile();
- private String[] dataTags;
- private DateFormat dateFormat;
+ private String format;
+ private String dateFormat;
public StarLinkProtocolDecoder(Protocol protocol) {
super(protocol);
@@ -60,13 +62,24 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder {
setDateFormat(Context.getConfig().getString(getProtocolName() + ".dateFormat", "yyMMddHHmmss"));
}
+ public String[] getFormat(long deviceId) {
+ return Context.getIdentityManager().lookupAttributeString(
+ deviceId, getProtocolName() + ".format", format, false, false).split(",");
+ }
+
public void setFormat(String format) {
- dataTags = format.split(",");
+ this.format = format;
+ }
+
+ public DateFormat getDateFormat(long deviceId) {
+ DateFormat dateFormat = new SimpleDateFormat(Context.getIdentityManager().lookupAttributeString(
+ deviceId, getProtocolName() + ".dateFormat", this.dateFormat, false, false));
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return dateFormat;
}
public void setDateFormat(String dateFormat) {
- this.dateFormat = new SimpleDateFormat(dateFormat);
- this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ this.dateFormat = dateFormat;
}
private double parseCoordinate(String value) {
@@ -128,6 +141,9 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder {
Integer lac = null, cid = null;
int event = 0;
+ String[] dataTags = getFormat(deviceSession.getDeviceId());
+ DateFormat dateFormat = getDateFormat(deviceSession.getDeviceId());
+
for (int i = 0; i < Math.min(data.length, dataTags.length); i++) {
if (data[i].isEmpty()) {
continue;
@@ -186,6 +202,9 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder {
cid = Integer.parseInt(data[i]);
}
break;
+ case "#CSS#":
+ position.set(Position.KEY_RSSI, Integer.parseInt(data[i]));
+ break;
case "#VIN#":
position.set(Position.KEY_POWER, Double.parseDouble(data[i]));
break;
@@ -201,6 +220,32 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder {
case "#ENG#":
position.set("engine", data[i].equals("1"));
break;
+ case "#SATU#":
+ position.set(Position.KEY_SATELLITES, Integer.parseInt(data[i]));
+ break;
+ case "#TS1#":
+ position.set("sensor1State", Integer.parseInt(data[i]));
+ break;
+ case "#TS2#":
+ position.set("sensor2State", Integer.parseInt(data[i]));
+ break;
+ case "#TD1#":
+ case "#TD2#":
+ StarLinkMessage.mEventReport_TDx message =
+ StarLinkMessage.mEventReport_TDx.parseFrom(DataConverter.parseBase64(data[i]));
+ position.set(
+ "sensor" + message.getSensorNumber() + "Id",
+ message.getSensorID());
+ position.set(
+ "sensor" + message.getSensorNumber() + "Temp",
+ message.getTemperature() * 0.1);
+ position.set(
+ "sensor" + message.getSensorNumber() + "Humidity",
+ message.getTemperature() * 0.1);
+ position.set(
+ "sensor" + message.getSensorNumber() + "Voltage",
+ message.getVoltage() * 0.001);
+ break;
default:
break;
}
diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
index 451b9ba32..76e3e6ecc 100644
--- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
@@ -479,20 +479,21 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
position.setTime(dateFormat.parse(values[index++] + values[index++]));
}
+ CellTower cellTower = new CellTower();
if (BitUtil.check(mask, 6)) {
- index += 1; // cell
+ cellTower.setCellId(Long.parseLong(values[index++], 16));
}
-
if (BitUtil.check(mask, 7)) {
- index += 1; // mcc
+ cellTower.setMobileCountryCode(Integer.parseInt(values[index++]));
}
-
if (BitUtil.check(mask, 8)) {
- index += 1; // mnc
+ cellTower.setMobileNetworkCode(Integer.parseInt(values[index++]));
}
-
if (BitUtil.check(mask, 9)) {
- index += 1; // lac
+ cellTower.setLocationAreaCode(Integer.parseInt(values[index++], 16));
+ }
+ if (cellTower.getCellId() != null) {
+ position.setNetwork(new Network(cellTower));
}
if (BitUtil.check(mask, 10)) {
@@ -531,16 +532,26 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_OUTPUT, Integer.parseInt(values[index++]));
}
- if (BitUtil.check(mask, 19)) {
- position.set("alertId", values[index++]);
- }
-
- if (BitUtil.check(mask, 20)) {
- position.set("alertModifier", values[index++]);
- }
-
- if (BitUtil.check(mask, 21)) {
- position.set("alertData", values[index++]);
+ if (type.equals("ALT")) {
+ if (BitUtil.check(mask, 19)) {
+ position.set("alertId", values[index++]);
+ }
+ if (BitUtil.check(mask, 20)) {
+ position.set("alertModifier", values[index++]);
+ }
+ if (BitUtil.check(mask, 21)) {
+ position.set("alertData", values[index++]);
+ }
+ } else {
+ if (BitUtil.check(mask, 19)) {
+ position.set("mode", Integer.parseInt(values[index++]));
+ }
+ if (BitUtil.check(mask, 20)) {
+ position.set("reason", Integer.parseInt(values[index++]));
+ }
+ if (BitUtil.check(mask, 21)) {
+ position.set(Position.KEY_INDEX, Integer.parseInt(values[index++]));
+ }
}
if (BitUtil.check(mask, 22)) {
@@ -676,6 +687,24 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Position decodeTravelReport(Channel channel, SocketAddress remoteAddress, String[] values) {
+ int index = 1;
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, null);
+
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, values[values.length - 1]);
+
+ return position;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -693,6 +722,8 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
if (prefix.length() < 5) {
return decodeUniversal(channel, remoteAddress, values);
+ } else if (prefix.endsWith("HTE")) {
+ return decodeTravelReport(channel, remoteAddress, values);
} else if (prefix.startsWith("ST9")) {
return decode9(channel, remoteAddress, values);
} else if (prefix.startsWith("ST4")) {
diff --git a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java
index b75addfae..230d29216 100644
--- a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2020 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.
@@ -24,6 +24,7 @@ import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
+import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
import java.net.SocketAddress;
@@ -109,6 +110,20 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
.any()
.compile();
+ private static final Pattern PATTERN_QZE = new PatternBuilder()
+ .text("QZE,")
+ .number("(d{15}),") // imei
+ .number("(d+),") // event
+ .number("(dd)(dd)(dddd),") // date (mmddyyyy)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("(-?d+.d+),") // latitude
+ .number("(-?d+.d+),") // longitude
+ .number("(d+),") // speed
+ .number("(d+),") // course
+ .expression("([AV]),") // validity
+ .expression("([01])") // ignition
+ .compile();
+
private Position position = null;
private Position decodeGprmc(
@@ -256,6 +271,35 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Position decodeQze(Channel channel, SocketAddress remoteAddress, String sentence) {
+
+ Parser parser = new Parser(PATTERN_QZE, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.set(Position.KEY_EVENT, parser.nextInt());
+
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+ position.setLatitude(parser.nextDouble());
+ position.setLongitude(parser.nextDouble());
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt()));
+ position.setCourse(parser.nextInt());
+ position.setValid(parser.next().equals("A"));
+
+ position.set(Position.KEY_IGNITION, parser.nextInt() > 0);
+
+ return position;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -308,6 +352,8 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
return decodeTrccr(deviceSession, sentence);
} else if (sentence.startsWith("$GPIOP")) {
return decodeGpiop(deviceSession, sentence);
+ } else if (sentence.startsWith("QZE")) {
+ return decodeQze(channel, remoteAddress, sentence);
}
return null;
diff --git a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java
index 3331ebb71..5822d6b8f 100644
--- a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java
@@ -230,10 +230,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
int battery = BcdUtil.readInteger(buf, 2);
- if (battery == 0) {
- battery = 100;
- }
- position.set(Position.KEY_BATTERY, battery);
+ position.set(Position.KEY_BATTERY_LEVEL, battery > 0 ? battery : 100);
}
@@ -284,7 +281,8 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
}
position.set(Position.KEY_G_SENSOR, "[" + accelerationX + "," + accelerationY + "," + accelerationZ + "]");
- position.set(Position.KEY_BATTERY_LEVEL, BcdUtil.readInteger(buf, 2));
+ int battery = BcdUtil.readInteger(buf, 2);
+ position.set(Position.KEY_BATTERY_LEVEL, battery > 0 ? battery : 100);
position.set(Position.KEY_DEVICE_TEMP, (int) buf.readByte());
position.set("lightSensor", BcdUtil.readInteger(buf, 2) * 0.1);
position.set(Position.KEY_BATTERY, BcdUtil.readInteger(buf, 2) * 0.1);
diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java
index 40b769869..0ea02b157 100644
--- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java
@@ -43,9 +43,9 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
private static final int IMAGE_PACKET_MAX = 2048;
- private boolean connectionless;
+ private final boolean connectionless;
private boolean extended;
- private Map<Long, ByteBuf> photos = new HashMap<>();
+ private final Map<Long, ByteBuf> photos = new HashMap<>();
public void setExtended(boolean extended) {
this.extended = extended;
@@ -208,7 +208,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.PREFIX_ADC + 2, readValue(buf, length, false));
break;
case 16:
- case 87:
position.set(Position.KEY_ODOMETER, readValue(buf, length, false));
break;
case 17:
@@ -223,9 +222,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
case 21:
position.set(Position.KEY_RSSI, readValue(buf, length, false));
break;
- case 24:
- readValue(buf, length, false); // speed
- break;
case 25:
case 26:
case 27:
@@ -255,34 +251,9 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
case 80:
position.set("workMode", readValue(buf, length, false));
break;
- case 81:
- position.set(Position.KEY_OBD_SPEED, readValue(buf, length, false));
- break;
- case 82:
- position.set(Position.KEY_THROTTLE, readValue(buf, length, false));
- break;
- case 83:
- position.set(Position.KEY_FUEL_USED, readValue(buf, length, false) * 0.1);
- break;
- case 84:
- position.set(Position.KEY_FUEL_LEVEL, readValue(buf, length, false) * 0.1);
- break;
- case 85:
- position.set(Position.KEY_RPM, readValue(buf, length, false));
- break;
case 90:
position.set(Position.KEY_DOOR, readValue(buf, length, false));
break;
- case 110:
- position.set(Position.KEY_FUEL_CONSUMPTION, readValue(buf, length, true) * 0.1);
- break;
- case 113:
- if (length == 1) {
- position.set(Position.KEY_BATTERY_LEVEL, readValue(buf, length, true));
- } else {
- position.set(Position.PREFIX_IO + id, readValue(buf, length, false));
- }
- break;
case 115:
position.set(Position.KEY_COOLANT_TEMP, readValue(buf, length, true) * 0.1);
break;
@@ -311,9 +282,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
case 199:
position.set(Position.KEY_ODOMETER_TRIP, readValue(buf, length, false));
break;
- case 235:
- position.set("oilLevel", readValue(buf, length, false));
- break;
case 236:
if (readValue(buf, length, false) == 1) {
position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED);
@@ -569,6 +537,29 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
int length = buf.readUnsignedShort();
if (id == 256) {
position.set(Position.KEY_VIN, buf.readSlice(length).toString(StandardCharsets.US_ASCII));
+ } else if (id == 385) {
+ ByteBuf data = buf.readSlice(length);
+ data.readUnsignedByte(); // data part
+ int index = 1;
+ while (data.isReadable()) {
+ int flags = data.readUnsignedByte();
+ if (BitUtil.from(flags, 4) > 0) {
+ position.set("beacon" + index + "Uuid", ByteBufUtil.hexDump(data.readSlice(16)));
+ position.set("beacon" + index + "Major", data.readUnsignedShort());
+ position.set("beacon" + index + "Minor", data.readUnsignedShort());
+ } else {
+ position.set("beacon" + index + "Namespace", ByteBufUtil.hexDump(data.readSlice(10)));
+ position.set("beacon" + index + "Instance", ByteBufUtil.hexDump(data.readSlice(6)));
+ }
+ position.set("beacon" + index + "Rssi", (int) data.readByte());
+ if (BitUtil.check(flags, 1)) {
+ position.set("beacon" + index + "Battery", data.readUnsignedShort() * 0.01);
+ }
+ if (BitUtil.check(flags, 2)) {
+ position.set("beacon" + index + "Temp", data.readUnsignedShort());
+ }
+ index += 1;
+ }
} else {
position.set(Position.PREFIX_IO + id, ByteBufUtil.hexDump(buf.readSlice(length)));
}
diff --git a/src/main/java/org/traccar/protocol/V680ProtocolDecoder.java b/src/main/java/org/traccar/protocol/V680ProtocolDecoder.java
index 0342404a6..40267022b 100644
--- a/src/main/java/org/traccar/protocol/V680ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/V680ProtocolDecoder.java
@@ -62,7 +62,7 @@ public class V680ProtocolDecoder extends BaseProtocolDecoder {
if (sentence.length() == 16) {
- getDeviceSession(channel, remoteAddress, sentence.substring(1, sentence.length()));
+ getDeviceSession(channel, remoteAddress, sentence.substring(1));
} else {
diff --git a/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java
index c132f194b..31a1bbb11 100644
--- a/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java
@@ -91,7 +91,7 @@ public class Xt2400ProtocolDecoder extends BaseProtocolDecoder {
return length;
}
- private Map<Short, byte[]> formats = new HashMap<>();
+ private final Map<Short, byte[]> formats = new HashMap<>();
public void setConfig(String configString) {
Pattern pattern = Pattern.compile(":wycfg pcr\\[\\d+] ([0-9a-fA-F]{2})[0-9a-fA-F]{2}([0-9a-fA-F]+)");