aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--setup/default.xml5
-rw-r--r--src/org/traccar/protocol/DwayProtocol.java47
-rw-r--r--src/org/traccar/protocol/DwayProtocolDecoder.java109
-rw-r--r--src/org/traccar/protocol/FlespiProtocol.java46
-rw-r--r--src/org/traccar/protocol/FlespiProtocolDecoder.java116
-rw-r--r--src/org/traccar/protocol/GenxProtocolDecoder.java19
-rw-r--r--src/org/traccar/protocol/MeitrackProtocolDecoder.java165
-rw-r--r--src/org/traccar/protocol/TotemProtocolDecoder.java256
-rw-r--r--test/org/traccar/protocol/DwayProtocolDecoderTest.java30
-rw-r--r--test/org/traccar/protocol/FlespiProtocolDecoderTest.java24
-rw-r--r--test/org/traccar/protocol/GenxProtocolDecoderTest.java5
-rw-r--r--test/org/traccar/protocol/MeitrackProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/TotemProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/WatchFrameDecoderTest.java5
14 files changed, 700 insertions, 139 deletions
diff --git a/setup/default.xml b/setup/default.xml
index 53ef5f4e3..d33e6dd27 100644
--- a/setup/default.xml
+++ b/setup/default.xml
@@ -217,6 +217,9 @@
<entry key='tlv.port'>5146</entry>
<entry key='esky.port'>5147</entry>
<entry key='genx.port'>5148</entry>
- <entry key='arnavi4.port'>5149</entry>
+ <entry key='flespi.port'>5149</entry>
+ <entry key='dway.port'>5150</entry>
+ <entry key='arnavi4.port'>5151</entry>
+
</properties>
diff --git a/src/org/traccar/protocol/DwayProtocol.java b/src/org/traccar/protocol/DwayProtocol.java
new file mode 100644
index 000000000..151d3fe01
--- /dev/null
+++ b/src/org/traccar/protocol/DwayProtocol.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 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.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.handler.codec.frame.LineBasedFrameDecoder;
+import org.jboss.netty.handler.codec.string.StringDecoder;
+import org.jboss.netty.handler.codec.string.StringEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.TrackerServer;
+
+import java.util.List;
+
+public class DwayProtocol extends BaseProtocol {
+
+ public DwayProtocol() {
+ super("dway");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ServerBootstrap(), getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
+ pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
+ pipeline.addLast("objectDecoder", new DwayProtocolDecoder(DwayProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/DwayProtocolDecoder.java b/src/org/traccar/protocol/DwayProtocolDecoder.java
new file mode 100644
index 000000000..993aa91b2
--- /dev/null
+++ b/src/org/traccar/protocol/DwayProtocolDecoder.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2017 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.jboss.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+public class DwayProtocolDecoder extends BaseProtocolDecoder {
+
+ public DwayProtocolDecoder(DwayProtocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("AA55,")
+ .number("d+,") // index
+ .number("(d+),") // imei
+ .number("d+,") // type
+ .number("(dd)(dd)(dd),") // date (yymmdd)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("(-?d+.d+),") // latitude
+ .number("(-?d+.d+),") // longitude
+ .number("(-?d+),") // altitude
+ .number("(d+.d+),") // speed
+ .number("(d+),") // course
+ .number("([01]{4}),") // input
+ .number("([01]{4}),") // output
+ .number("([01])([01])([01])([01]),") // flags
+ .number("(d+),") // battery
+ .number("(d+),") // adc1
+ .number("(d+),") // adc2
+ .number("(d+)") // driver
+ .compile();
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ String sentence = (String) msg;
+ if (sentence.startsWith(">H")) {
+ if (channel != null) {
+ channel.write(">ALIVE\r\n");
+ }
+ return null;
+ }
+
+ 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();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setTime(parser.nextDateTime());
+ position.setLatitude(parser.nextDouble());
+ position.setLongitude(parser.nextDouble());
+ position.setAltitude(parser.nextDouble(0));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0)));
+ position.setCourse(parser.nextDouble(0));
+
+ position.set(Position.KEY_INPUT, parser.nextBinInt());
+ position.set(Position.KEY_OUTPUT, parser.nextBinInt());
+
+ position.setValid(parser.next().equals("1"));
+
+ position.set(Position.KEY_IGNITION, parser.next().equals("1"));
+ position.set(Position.KEY_CHARGE, parser.next().equals("1"));
+
+ if (parser.next().equals("1")) {
+ position.set(Position.KEY_ALARM, Position.ALARM_SHOCK);
+ }
+
+ position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001);
+ position.set(Position.PREFIX_ADC + 1, parser.nextInt() * 0.001);
+ position.set(Position.PREFIX_ADC + 2, parser.nextInt() * 0.001);
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next());
+
+ return position;
+ }
+
+}
diff --git a/src/org/traccar/protocol/FlespiProtocol.java b/src/org/traccar/protocol/FlespiProtocol.java
new file mode 100644
index 000000000..d22bd7ae0
--- /dev/null
+++ b/src/org/traccar/protocol/FlespiProtocol.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 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.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
+import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
+import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.TrackerServer;
+
+import java.util.List;
+
+public class FlespiProtocol extends BaseProtocol {
+
+ public FlespiProtocol() {
+ super("flespi");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ServerBootstrap(), getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("httpEncoder", new HttpResponseEncoder());
+ pipeline.addLast("httpDecoder", new HttpRequestDecoder());
+ pipeline.addLast("httpAggregator", new HttpChunkAggregator(Integer.MAX_VALUE));
+ pipeline.addLast("objectDecoder", new FlespiProtocolDecoder(FlespiProtocol.this));
+ }
+ });
+ }
+}
diff --git a/src/org/traccar/protocol/FlespiProtocolDecoder.java b/src/org/traccar/protocol/FlespiProtocolDecoder.java
new file mode 100644
index 000000000..799d78ecb
--- /dev/null
+++ b/src/org/traccar/protocol/FlespiProtocolDecoder.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2017 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.jboss.netty.channel.Channel;
+import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
+import org.jboss.netty.handler.codec.http.HttpRequest;
+import org.jboss.netty.handler.codec.http.HttpResponse;
+import org.jboss.netty.handler.codec.http.HttpResponseStatus;
+import org.jboss.netty.handler.codec.http.HttpVersion;
+import org.jboss.netty.handler.codec.http.HttpHeaders;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.model.Position;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonNumber;
+import javax.json.JsonObject;
+import javax.json.JsonString;
+import java.io.StringReader;
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Date;
+
+public class FlespiProtocolDecoder extends BaseProtocolDecoder {
+
+ public FlespiProtocolDecoder(FlespiProtocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ HttpRequest request = (HttpRequest) msg;
+ JsonArray result = Json.createReader(new StringReader(request.getContent().toString(StandardCharsets.UTF_8)))
+ .readArray();
+ List<Position> positions = new LinkedList<>();
+ for (int i = 0; i < result.size(); i++) {
+ JsonObject message = result.getJsonObject(i);
+ JsonString ident = message.getJsonString("ident");
+ if (ident == null) {
+ continue;
+ }
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, ident.getString());
+ if (deviceSession == null) {
+ continue;
+ }
+ Position position = new Position();
+ position.setDeviceId(deviceSession.getDeviceId());
+ decodePosition(message, position);
+ positions.add(position);
+ }
+
+ sendResponse(channel, HttpResponseStatus.OK);
+ return positions;
+ }
+
+ private void sendResponse(Channel channel, HttpResponseStatus status) {
+ if (channel != null) {
+ HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status);
+ response.headers().add(HttpHeaders.Names.CONTENT_LENGTH, 0);
+ channel.write(response);
+ }
+ }
+
+ private void decodePosition(JsonObject object, Position position) {
+ position.setProtocol(getProtocolName());
+
+ Date deviceTime = new Date((long) object.getJsonNumber("timestamp").doubleValue() * 1000);
+ position.setTime(deviceTime);
+ JsonNumber lat = object.getJsonNumber("position.latitude");
+ JsonNumber lon = object.getJsonNumber("position.longitude");
+ if (lat != null && lon != null) {
+ position.setLatitude(lat.doubleValue());
+ position.setLongitude(lon.doubleValue());
+ } else {
+ getLastLocation(position, deviceTime);
+ }
+ JsonNumber speed = object.getJsonNumber("position.speed");
+ if (speed != null) {
+ position.setSpeed(speed.doubleValue());
+ }
+ JsonNumber course = object.getJsonNumber("position.direction");
+ if (course != null) {
+ position.setCourse(course.doubleValue());
+ }
+ JsonNumber altitude = object.getJsonNumber("position.altitude");
+ if (altitude != null) {
+ position.setAltitude(altitude.doubleValue());
+ }
+
+ position.setValid(object.getBoolean("position.valid", true));
+ position.set(Position.KEY_SATELLITES, object.getInt("position.satellites", 0));
+
+ if (object.getBoolean("alarm.event.trigger", false)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
+ }
+ }
+}
diff --git a/src/org/traccar/protocol/GenxProtocolDecoder.java b/src/org/traccar/protocol/GenxProtocolDecoder.java
index 3b716796c..ebf6f2b53 100644
--- a/src/org/traccar/protocol/GenxProtocolDecoder.java
+++ b/src/org/traccar/protocol/GenxProtocolDecoder.java
@@ -19,6 +19,7 @@ import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.Context;
import org.traccar.DeviceSession;
+import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
import java.net.SocketAddress;
@@ -68,6 +69,24 @@ public class GenxProtocolDecoder extends BaseProtocolDecoder {
case 4:
position.setLongitude(Double.parseDouble(values[i]));
break;
+ case 11:
+ position.set(Position.KEY_IGNITION, values[i].equals("ON"));
+ break;
+ case 13:
+ position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(values[i])));
+ break;
+ case 17:
+ position.setCourse(Integer.parseInt(values[i]));
+ break;
+ case 23:
+ position.set(Position.KEY_ODOMETER, Double.parseDouble(values[i]) * 1000);
+ break;
+ case 27:
+ position.setAltitude(UnitsConverter.metersFromFeet(Integer.parseInt(values[i])));
+ break;
+ case 46:
+ position.set(Position.KEY_SATELLITES, Integer.parseInt(values[i]));
+ break;
default:
break;
}
diff --git a/src/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/org/traccar/protocol/MeitrackProtocolDecoder.java
index efc9c24db..5b67aebe3 100644
--- a/src/org/traccar/protocol/MeitrackProtocolDecoder.java
+++ b/src/org/traccar/protocol/MeitrackProtocolDecoder.java
@@ -16,6 +16,7 @@
package org.traccar.protocol;
import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.Context;
@@ -37,6 +38,8 @@ import java.util.regex.Pattern;
public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
+ private ChannelBuffer photo;
+
public MeitrackProtocolDecoder(MeitrackProtocol protocol) {
super(protocol);
}
@@ -109,7 +112,7 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
}
}
- private Position decodeRegularMessage(Channel channel, SocketAddress remoteAddress, ChannelBuffer buf) {
+ private Position decodeRegular(Channel channel, SocketAddress remoteAddress, ChannelBuffer buf) {
Parser parser = new Parser(PATTERN, buf.toString(StandardCharsets.US_ASCII));
if (!parser.matches()) {
@@ -219,13 +222,13 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
if (parser.hasNext()) {
for (String temp : parser.next().split("\\|")) {
- int index = Integer.valueOf(temp.substring(0, 2), 16);
+ int index = Integer.parseInt(temp.substring(0, 2), 16);
if (protocol >= 3) {
- double value = Short.valueOf(temp.substring(2), 16);
+ double value = (short) Integer.parseInt(temp.substring(2), 16);
position.set(Position.PREFIX_TEMP + index, value * 0.01);
} else {
- double value = Byte.valueOf(temp.substring(2, 4), 16);
- value += (value < 0 ? -0.01 : 0.01) * Integer.valueOf(temp.substring(4), 16);
+ double value = Byte.parseByte(temp.substring(2, 4), 16);
+ value += (value < 0 ? -0.01 : 0.01) * Integer.parseInt(temp.substring(4), 16);
position.set(Position.PREFIX_TEMP + index, value);
}
}
@@ -234,7 +237,7 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
return position;
}
- private List<Position> decodeBinaryMessage(Channel channel, SocketAddress remoteAddress, ChannelBuffer buf) {
+ private List<Position> decodeBinaryC(Channel channel, SocketAddress remoteAddress, ChannelBuffer buf) {
List<Position> positions = new LinkedList<>();
String flag = buf.toString(2, 1, StandardCharsets.US_ASCII);
@@ -308,6 +311,108 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
return positions;
}
+ private List<Position> decodeBinaryE(Channel channel, SocketAddress remoteAddress, ChannelBuffer buf) {
+ List<Position> positions = new LinkedList<>();
+
+ buf.readerIndex(buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ',') + 1);
+ String imei = buf.readBytes(15).toString(StandardCharsets.US_ASCII);
+ buf.skipBytes(1 + 3 + 1);
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ buf.readUnsignedInt(); // remaining cache
+ int count = buf.readUnsignedShort();
+
+ for (int i = 0; i < count; i++) {
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ buf.readUnsignedShort(); // length
+ buf.readUnsignedShort(); // index
+
+ int paramCount = buf.readUnsignedByte();
+ for (int j = 0; j < paramCount; j++) {
+ int id = buf.readUnsignedByte();
+ switch (id) {
+ case 0x01:
+ position.set(Position.KEY_EVENT, buf.readUnsignedByte());
+ break;
+ case 0x05:
+ position.setValid(buf.readUnsignedByte() > 0);
+ break;
+ case 0x06:
+ position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ break;
+ default:
+ buf.readUnsignedByte();
+ break;
+ }
+ }
+
+ paramCount = buf.readUnsignedByte();
+ for (int j = 0; j < paramCount; j++) {
+ int id = buf.readUnsignedByte();
+ switch (id) {
+ case 0x08:
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort()));
+ break;
+ case 0x09:
+ position.setCourse(buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x0B:
+ position.setAltitude(buf.readShort());
+ break;
+ default:
+ buf.readUnsignedShort();
+ break;
+ }
+ }
+
+ paramCount = buf.readUnsignedByte();
+ for (int j = 0; j < paramCount; j++) {
+ int id = buf.readUnsignedByte();
+ switch (id) {
+ case 0x02:
+ position.setLatitude(buf.readInt() * 0.000001);
+ break;
+ case 0x03:
+ position.setLongitude(buf.readInt() * 0.000001);
+ break;
+ case 0x04:
+ position.setTime(new Date((946684800 + buf.readUnsignedInt()) * 1000)); // 2000-01-01
+ break;
+ default:
+ buf.readUnsignedInt();
+ break;
+ }
+ }
+
+ paramCount = buf.readUnsignedByte();
+ for (int j = 0; j < paramCount; j++) {
+ buf.readUnsignedByte(); // id
+ buf.skipBytes(buf.readUnsignedByte()); // value
+ }
+
+ positions.add(position);
+ }
+
+ return positions;
+ }
+
+ private void requestPhotoPacket(Channel channel, String imei, int index) {
+ if (channel != null) {
+ String content = "D00,camera_picture.jpg," + index;
+ int length = 1 + imei.length() + 1 + content.length() + 5;
+ String response = String.format("@@O%02d,%s,%s*", length, imei, content);
+ response += Checksum.sum(response) + "\r\n";
+ channel.write(response);
+ }
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -315,25 +420,49 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
ChannelBuffer buf = (ChannelBuffer) msg;
int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ',');
+ String imei = buf.toString(index + 1, 15, StandardCharsets.US_ASCII);
index = buf.indexOf(index + 1, buf.writerIndex(), (byte) ',');
-
String type = buf.toString(index + 1, 3, StandardCharsets.US_ASCII);
+
switch (type) {
- case "D03":
- if (channel != null) {
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
- String imei = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getUniqueId();
- String content = "D00,camera_picture.jpg,0";
- int length = 1 + imei.length() + 1 + content.length() + 5;
- String response = String.format("@@O%02d,%s,%s*", length, imei, content);
- response += Checksum.sum(response) + "\r\n";
- channel.write(response);
+ case "D00":
+ index = buf.indexOf(index + 1 + type.length() + 1, buf.writerIndex(), (byte) ',') + 1;
+ int endIndex = buf.indexOf(index, buf.writerIndex(), (byte) ',');
+ int total = Integer.parseInt(buf.toString(index, endIndex - index, StandardCharsets.US_ASCII));
+ index = endIndex + 1;
+ endIndex = buf.indexOf(index, buf.writerIndex(), (byte) ',');
+ int current = Integer.parseInt(buf.toString(index, endIndex - index, StandardCharsets.US_ASCII));
+
+ buf.readerIndex(endIndex + 1);
+ photo.writeBytes(buf.readBytes(buf.readableBytes() - 1 - 2 - 2));
+
+ if (current == total - 1) {
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(getDeviceSession(channel, remoteAddress, imei).getDeviceId());
+
+ getLastLocation(position, null);
+
+ position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(imei, photo, "jpg"));
+ photo = null;
+
+ return position;
+ } else {
+ if ((current + 1) % 8 == 0) {
+ requestPhotoPacket(channel, imei, current + 1);
+ }
+ return null;
}
+ case "D03":
+ photo = ChannelBuffers.dynamicBuffer();
+ requestPhotoPacket(channel, imei, 0);
return null;
case "CCC":
- return decodeBinaryMessage(channel, remoteAddress, buf);
+ return decodeBinaryC(channel, remoteAddress, buf);
+ case "CCE":
+ return decodeBinaryE(channel, remoteAddress, buf);
default:
- return decodeRegularMessage(channel, remoteAddress, buf);
+ return decodeRegular(channel, remoteAddress, buf);
}
}
diff --git a/src/org/traccar/protocol/TotemProtocolDecoder.java b/src/org/traccar/protocol/TotemProtocolDecoder.java
index 3c2dee8ec..a3e8c9921 100644
--- a/src/org/traccar/protocol/TotemProtocolDecoder.java
+++ b/src/org/traccar/protocol/TotemProtocolDecoder.java
@@ -131,7 +131,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
private static final Pattern PATTERN4 = new PatternBuilder()
.text("$$") // header
.number("dddd") // length
- .text("AA") // type
+ .expression("A[ABC]") // type
.number("(d+)|") // imei
.number("(x{8})") // status
.number("(dd)(dd)(dd)") // date (yymmdd)
@@ -182,15 +182,138 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
}
}
+ private boolean decode12(Position position, Parser parser, Pattern pattern) {
+
+ if (parser.hasNext()) {
+ position.set(Position.KEY_ALARM, decodeAlarm(Short.parseShort(parser.next(), 16)));
+ }
+ DateBuilder dateBuilder = new DateBuilder();
+ int year = 0, month = 0, day = 0;
+ if (pattern == PATTERN2) {
+ day = parser.nextInt(0);
+ month = parser.nextInt(0);
+ year = parser.nextInt(0);
+ }
+ dateBuilder.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
+
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setSpeed(parser.nextDouble(0));
+ position.setCourse(parser.nextDouble(0));
+
+ if (pattern == PATTERN1) {
+ day = parser.nextInt(0);
+ month = parser.nextInt(0);
+ year = parser.nextInt(0);
+ }
+ if (year == 0) {
+ return false; // ignore invalid data
+ }
+ dateBuilder.setDate(year, month, day);
+ position.setTime(dateBuilder.getDate());
+
+ if (pattern == PATTERN1) {
+ position.set(Position.KEY_PDOP, parser.nextDouble());
+ position.set(Position.KEY_HDOP, parser.nextDouble());
+ position.set(Position.KEY_VDOP, parser.nextDouble());
+ } else {
+ position.set(Position.KEY_HDOP, parser.nextDouble());
+ }
+
+ position.set(Position.PREFIX_IO + 1, parser.next());
+ if (pattern == PATTERN1) {
+ position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.01);
+ } else {
+ position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1);
+ }
+ position.set(Position.KEY_POWER, parser.nextDouble(0));
+ position.set(Position.PREFIX_ADC + 1, parser.next());
+
+ int lac = parser.nextHexInt(0);
+ int cid = parser.nextHexInt(0);
+ if (lac != 0 && cid != 0) {
+ position.setNetwork(new Network(CellTower.fromLacCid(lac, cid)));
+ }
+
+ position.set(Position.PREFIX_TEMP + 1, parser.next());
+ position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000);
+
+ return true;
+ }
+
+ private boolean decode3(Position position, Parser parser) {
+
+ if (parser.hasNext()) {
+ position.set(Position.KEY_ALARM, decodeAlarm(Short.parseShort(parser.next(), 16)));
+ }
+
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+
+ position.set(Position.PREFIX_IO + 1, parser.next());
+ position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1);
+ position.set(Position.KEY_POWER, parser.nextDouble(0));
+ position.set(Position.PREFIX_ADC + 1, parser.next());
+ position.set(Position.PREFIX_ADC + 2, parser.next());
+ position.set(Position.PREFIX_TEMP + 1, parser.next());
+ position.set(Position.PREFIX_TEMP + 2, parser.next());
+
+ position.setNetwork(new Network(
+ CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0))));
+
+ position.setValid(parser.next().equals("A"));
+ position.set(Position.KEY_SATELLITES, parser.nextInt());
+ position.setCourse(parser.nextDouble(0));
+ position.setSpeed(parser.nextDouble(0));
+ position.set(Position.KEY_PDOP, parser.nextDouble());
+ position.set(Position.KEY_ODOMETER, parser.nextInt(0) * 1000);
+
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+
+ return true;
+ }
+
+ private boolean decode4(Position position, Parser parser) {
+
+ position.set(Position.KEY_STATUS, parser.next());
+
+ position.setTime(parser.nextDateTime());
+
+ position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1);
+ position.set(Position.KEY_POWER, parser.nextDouble(0));
+
+ position.set(Position.PREFIX_ADC + 1, parser.next());
+ position.set(Position.PREFIX_ADC + 2, parser.next());
+ position.set(Position.PREFIX_ADC + 3, parser.next());
+ position.set(Position.PREFIX_ADC + 4, parser.next());
+ position.set(Position.PREFIX_TEMP + 1, parser.next());
+ position.set(Position.PREFIX_TEMP + 2, parser.next());
+
+ CellTower cellTower = CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0));
+ position.set(Position.KEY_SATELLITES, parser.nextInt(0));
+ cellTower.setSignalStrength(parser.nextInt(0));
+ position.setNetwork(new Network(cellTower));
+
+ position.setCourse(parser.nextDouble(0));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0)));
+ position.set(Position.KEY_HDOP, parser.nextDouble(0));
+ position.set(Position.KEY_ODOMETER, parser.nextInt(0) * 1000);
+
+ position.setValid(true);
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+
+ return true;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
-
- // Determine format
Pattern pattern = PATTERN3;
- if (sentence.indexOf("AA") == 6) {
+ if (sentence.indexOf("A") == 6) {
pattern = PATTERN4;
} else if (sentence.contains("$GPRMC")) {
pattern = PATTERN1;
@@ -215,123 +338,24 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
}
position.setDeviceId(deviceSession.getDeviceId());
+ boolean result;
if (pattern == PATTERN1 || pattern == PATTERN2) {
- if (parser.hasNext()) {
- position.set(Position.KEY_ALARM, decodeAlarm(Short.parseShort(parser.next(), 16)));
- }
- DateBuilder dateBuilder = new DateBuilder();
- int year = 0, month = 0, day = 0;
- if (pattern == PATTERN2) {
- day = parser.nextInt(0);
- month = parser.nextInt(0);
- year = parser.nextInt(0);
- }
- dateBuilder.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
-
- position.setValid(parser.next().equals("A"));
- position.setLatitude(parser.nextCoordinate());
- position.setLongitude(parser.nextCoordinate());
- position.setSpeed(parser.nextDouble(0));
- position.setCourse(parser.nextDouble(0));
-
- if (pattern == PATTERN1) {
- day = parser.nextInt(0);
- month = parser.nextInt(0);
- year = parser.nextInt(0);
- }
- if (year == 0) {
- return null; // ignore invalid data
- }
- dateBuilder.setDate(year, month, day);
- position.setTime(dateBuilder.getDate());
-
- if (pattern == PATTERN1) {
- position.set(Position.KEY_PDOP, parser.nextDouble());
- position.set(Position.KEY_HDOP, parser.nextDouble());
- position.set(Position.KEY_VDOP, parser.nextDouble());
- } else {
- position.set(Position.KEY_HDOP, parser.nextDouble());
- }
-
- position.set(Position.PREFIX_IO + 1, parser.next());
- if (pattern == PATTERN1) {
- position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.01);
- } else {
- position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1);
- }
- position.set(Position.KEY_POWER, parser.nextDouble(0));
- position.set(Position.PREFIX_ADC + 1, parser.next());
-
- int lac = parser.nextHexInt(0);
- int cid = parser.nextHexInt(0);
- if (lac != 0 && cid != 0) {
- position.setNetwork(new Network(CellTower.fromLacCid(lac, cid)));
- }
-
- position.set(Position.PREFIX_TEMP + 1, parser.next());
- position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000);
-
+ result = decode12(position, parser, pattern);
} else if (pattern == PATTERN3) {
- if (parser.hasNext()) {
- position.set(Position.KEY_ALARM, decodeAlarm(Short.parseShort(parser.next(), 16)));
- }
-
- position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
-
- position.set(Position.PREFIX_IO + 1, parser.next());
- position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1);
- position.set(Position.KEY_POWER, parser.nextDouble(0));
- position.set(Position.PREFIX_ADC + 1, parser.next());
- position.set(Position.PREFIX_ADC + 2, parser.next());
- position.set(Position.PREFIX_TEMP + 1, parser.next());
- position.set(Position.PREFIX_TEMP + 2, parser.next());
-
- position.setNetwork(new Network(
- CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0))));
-
- position.setValid(parser.next().equals("A"));
- position.set(Position.KEY_SATELLITES, parser.nextInt());
- position.setCourse(parser.nextDouble(0));
- position.setSpeed(parser.nextDouble(0));
- position.set(Position.KEY_PDOP, parser.nextDouble());
- position.set(Position.KEY_ODOMETER, parser.nextInt(0) * 1000);
-
- position.setLatitude(parser.nextCoordinate());
- position.setLongitude(parser.nextCoordinate());
-
- } else if (pattern == PATTERN4) {
- position.set(Position.KEY_STATUS, parser.next());
-
- position.setTime(parser.nextDateTime());
-
- position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1);
- position.set(Position.KEY_POWER, parser.nextDouble(0));
-
- position.set(Position.PREFIX_ADC + 1, parser.next());
- position.set(Position.PREFIX_ADC + 2, parser.next());
- position.set(Position.PREFIX_ADC + 3, parser.next());
- position.set(Position.PREFIX_ADC + 4, parser.next());
- position.set(Position.PREFIX_TEMP + 1, parser.next());
- position.set(Position.PREFIX_TEMP + 2, parser.next());
-
- CellTower cellTower = CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0));
- position.set(Position.KEY_SATELLITES, parser.nextInt(0));
- cellTower.setSignalStrength(parser.nextInt(0));
- position.setNetwork(new Network(cellTower));
-
- position.setCourse(parser.nextDouble(0));
- position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0)));
- position.set(Position.KEY_HDOP, parser.nextDouble(0));
- position.set(Position.KEY_ODOMETER, parser.nextInt(0) * 1000);
-
- position.setValid(true);
- position.setLatitude(parser.nextCoordinate());
- position.setLongitude(parser.nextCoordinate());
+ result = decode3(position, parser);
+ } else {
+ result = decode4(position, parser);
}
+
if (channel != null) {
- channel.write("ACK OK\r\n");
+ if (pattern == PATTERN4) {
+ channel.write("$$0014AA" + sentence.substring(sentence.length() - 6));
+ } else {
+ channel.write("ACK OK\r\n");
+ }
}
- return position;
+
+ return result ? position : null;
}
}
diff --git a/test/org/traccar/protocol/DwayProtocolDecoderTest.java b/test/org/traccar/protocol/DwayProtocolDecoderTest.java
new file mode 100644
index 000000000..481382535
--- /dev/null
+++ b/test/org/traccar/protocol/DwayProtocolDecoderTest.java
@@ -0,0 +1,30 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class DwayProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ DwayProtocolDecoder decoder = new DwayProtocolDecoder(new DwayProtocol());
+
+ verifyNull(decoder, text(
+ "AA55,36,10024,1,171025,161055,36.0294,-79.7881,201, 2.5,111,1000,0000,00000,3578,0,0,0,D"));
+
+ verifyNull(decoder, text(
+ "AA55,115,318,1,171024,195059,28.0153,-82.4761,3, 1.0,319,1000,0000,00000,4244,0,0,0,D"));
+
+ verifyNull(decoder, text(
+ "AA55,117,318,1,171025,153758,28.0152,-82.4759,19, 0.6,319,1000,0000,10000,4242,0,0,0,D"));
+
+ verifyPosition(decoder, text(
+ "AA55,1,123456,1,140101,101132,22.5500,113.6770,75,70.5,320,1100,0011,1110,3950,33000,24000,12345678"));
+
+ verifyNull(decoder, text(
+ ">H12345678"));
+
+ }
+
+}
diff --git a/test/org/traccar/protocol/FlespiProtocolDecoderTest.java b/test/org/traccar/protocol/FlespiProtocolDecoderTest.java
new file mode 100644
index 000000000..b23da024a
--- /dev/null
+++ b/test/org/traccar/protocol/FlespiProtocolDecoderTest.java
@@ -0,0 +1,24 @@
+package org.traccar.protocol;
+
+import org.jboss.netty.handler.codec.http.HttpMethod;
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class FlespiProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ FlespiProtocolDecoder decoder = new FlespiProtocolDecoder(new FlespiProtocol());
+
+ verifyPositions(decoder, request(HttpMethod.POST, "/",
+ buffer("[{\"position.speed\":0,\"position.latitude\":53.90573,\"time.valid.status\":true,\"timestamp\":1506956075,\"position.satellites\":10,\"message.buffered.status\":false,\"business.mode.status\":true,\"gps.status\":true,\"position.longitude\":27.455848,\"position.direction\":0,\"ident\":\"605630\"},{\"siren.status\":false,\"business.mode.status\":true,\"position.satellites\":8,\"timestamp\":1506695785,\"led.status\":false,\"position.latitude\":53.905569,\"position.longitude\":27.455986,\"position.speed\":0,\"gradual.stop.status\":false,\"position.direction\":262.643854,\"hardware.version.enum\":223,\"vehicle.mileage\":160,\"message.buffered.status\":false,\"blinkers.status\":false,\"ident\":\"605630\",\"position.altitude\":233.48,\"immobilizer.status\":false}]")));
+
+ verifyPositions(decoder, request(HttpMethod.POST, "/",
+ buffer("[{\"geofence.inside.status\":false,\"position.valid\":false,\"ain#4\":0,\"rs232.sensor.value#1\":0,\"position.direction\":0,\"rs232.sensor.value#0\":0,\"position.speed\":0,\"position.latitude\":0,\"refrigerator.sensor.temperature#1\":62.5,\"gnss.antenna.cut.status\":true,\"din#4\":3,\"ain#3\":0,\"refrigerator.sensor.temperature#3\":71.4,\"position.altitude\":0,\"din#2\":3,\"shock.event.trigger\":false,\"alarm.mode.status\":false,\"ibutton.event.connect\":false,\"refrigerator.sensor.temperature#4\":66.7,\"internal.battery.voltage.limit.lower.status\":false,\"ain#2\":0,\"gsm.signal.level\":0,\"refrigerator.connection.status\":0,\"position.satellites\":0,\"din#1\":3,\"external.powersource.voltage.range.outside.status\":false,\"refrigerator.sensor.temperature#2\":68.2,\"incline.event.trigger\":false,\"alarm.event.trigger\":false,\"movement.status\":true,\"refrigerator.sensor.temperature#6\":68.9,\"ident\":\"50\",\"timestamp\":946684840,\"engine.ignition.status\":true,\"gsm.sim.status\":true,\"record.seqnum\":8165,\"external.powersource.voltage\":15.298,\"gnss.enum\":\"glonass\",\"position.longitude\":0,\"battery.voltage\":4.088,\"refrigerator.sensor.temperature#5\":71.3,\"din#3\":3,\"ain#1\":0,\"internal.bus.supply.voltage.range.outside.status\":false},{\"geofence.inside.status\":false,\"position.valid\":true,\"ain#4\":0,\"rs232.sensor.value#1\":0,\"position.direction\":0,\"rs232.sensor.value#0\":0,\"position.speed\":0,\"position.latitude\":57.986744,\"refrigerator.sensor.temperature#1\":74.1,\"gnss.antenna.cut.status\":false,\"din#4\":3,\"ain#3\":0,\"position.hdop\":21.1,\"refrigerator.sensor.temperature#3\":71.4,\"position.altitude\":219,\"din#2\":3,\"shock.event.trigger\":false,\"alarm.mode.status\":false,\"ibutton.event.connect\":false,\"refrigerator.sensor.temperature#4\":70.5,\"internal.battery.voltage.limit.lower.status\":false,\"ain#2\":0,\"gsm.signal.level\":0,\"refrigerator.connection.status\":0,\"position.satellites\":5,\"din#1\":3,\"external.powersource.voltage.range.outside.status\":false,\"refrigerator.sensor.temperature#2\":71.3,\"incline.event.trigger\":false,\"alarm.event.trigger\":false,\"movement.status\":true,\"refrigerator.sensor.temperature#6\":69.3,\"ident\":\"50\",\"timestamp\":1392272112,\"engine.ignition.status\":true,\"gsm.sim.status\":true,\"record.seqnum\":8174,\"external.powersource.voltage\":15.303,\"gnss.enum\":\"glonass\",\"position.longitude\":56.207576,\"battery.voltage\":3.934,\"refrigerator.sensor.temperature#5\":68.1,\"din#3\":3,\"ain#1\":0,\"internal.bus.supply.voltage.range.outside.status\":false}]")));
+
+ verifyPositions(decoder, request(HttpMethod.POST, "/",
+ buffer("[{\"ain#1\":1,\"ain#2\":0,\"ain#3\":0,\"ain#4\":0,\"alarm.event.trigger\":true,\"custom.SOS\":1,\"custom.dparam\":3.141593,\"custom.ign\":1,\"custom.iparam\":-55,\"custom.tparam\":\"lorem\",\"din#1\":false,\"din#10\":false,\"din#11\":false,\"din#12\":false,\"din#13\":false,\"din#14\":false,\"din#15\":false,\"din#16\":false,\"din#17\":false,\"din#18\":false,\"din#19\":false,\"din#2\":false,\"din#20\":false,\"din#21\":false,\"din#22\":false,\"din#23\":false,\"din#24\":false,\"din#25\":false,\"din#26\":false,\"din#27\":false,\"din#28\":false,\"din#29\":false,\"din#3\":false,\"din#30\":false,\"din#31\":false,\"din#32\":false,\"din#4\":false,\"din#5\":false,\"din#6\":false,\"din#7\":false,\"din#8\":false,\"din#9\":false,\"dout#1\":false,\"dout#10\":false,\"dout#11\":false,\"dout#12\":false,\"dout#13\":false,\"dout#14\":false,\"dout#15\":false,\"dout#16\":false,\"dout#17\":false,\"dout#18\":false,\"dout#19\":false,\"dout#2\":false,\"dout#20\":false,\"dout#21\":false,\"dout#22\":false,\"dout#23\":false,\"dout#24\":false,\"dout#25\":false,\"dout#26\":false,\"dout#27\":false,\"dout#28\":false,\"dout#29\":false,\"dout#3\":false,\"dout#30\":false,\"dout#31\":false,\"dout#32\":false,\"dout#4\":false,\"dout#5\":false,\"dout#6\":false,\"dout#7\":false,\"dout#8\":false,\"dout#9\":false,\"ident\":\"namo:namo\",\"position.altitude\":300,\"position.direction\":0,\"position.hdop\":1.1,\"position.latitude\":53.90821,\"position.longitude\":27.524165,\"position.satellites\":7,\"position.speed\":0,\"timestamp\":1508508510.013227}]")));
+ }
+
+} \ No newline at end of file
diff --git a/test/org/traccar/protocol/GenxProtocolDecoderTest.java b/test/org/traccar/protocol/GenxProtocolDecoderTest.java
index 43d9e7d6e..9c49839c4 100644
--- a/test/org/traccar/protocol/GenxProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/GenxProtocolDecoderTest.java
@@ -16,11 +16,14 @@ public class GenxProtocolDecoderTest extends ProtocolTest {
verifyPosition(decoder, text(
"000036004130,08/31/2017 17:24:37,45.47257,-73.65506,3,0,117,1.14,124,ON,1489,0,5,N,0,0.000,-95.0,-1.0,0,0.0000,0.0000,0.000,0,0.00,0.00,0.00,NA,U,UUU,0,-95.0,U"));
- decoder.setReportColumns("1,2,3,4");
+ decoder.setReportColumns("1,2,3,4,13,17,10,23,27,11,7,8,46,56,59,70,74,75,77,89,90,93,99,107,112,113,114,176,175,178,181,182");
verifyPosition(decoder, text(
"000036035855,04/16/2017 21:19:07,45.46485,-73.65424,24,32,61:213,342.51,157,ON,20984,0,12,O,18,0.000,95.0,24.0,1990,64.0894,0.0219,316.009,71,0.00,16.78,5.10,NA,U,UUU,0,-95.0,U"));
+ verifyPosition(decoder, text(
+ "000036004129,10/20/2017 00:54:27,43.44638,-79.68616,36,310,6,4954.40,321,ON,35377,0,12,O,13,0.000,85.6,36.0,1573,451.2514,0.0012,5260.953,0,0.00,122.48,33.17,NA,U,UUU,0,-95.0,U"));
+
}
}
diff --git a/test/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/test/org/traccar/protocol/MeitrackProtocolDecoderTest.java
index 07411dbc8..4ec2211bc 100644
--- a/test/org/traccar/protocol/MeitrackProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/MeitrackProtocolDecoderTest.java
@@ -11,6 +11,12 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest {
MeitrackProtocolDecoder decoder = new MeitrackProtocolDecoder(new MeitrackProtocol());
+ verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN,
+ "24245f3237382c3836353738393032313434373233322c4343452c5b00000003005000130006012305010608070d15001b0006080000091e010a09000b2e0019a1011af90106025c033300039be60c06044f6678210c6f1806000d48db06001c41000000010e0cf60113002005912b830001ff5000130006012305010608070d15001b0006080000091e010a09000b2e0019a0011af90106025c033300039be60c0604506678210c6f1806000d49db06001c41000000010e0cf60113002005912b830001ff5000130006012305010608070d15001b0006080000091e010a09000b2e0019a1011af90106025c033300039be60c0604516678210c6f1806000d4adb06001c41000000010e0cf60113002005912b830001ff2a37460d0a"));
+
+ verifyPosition(decoder, buffer(
+ "$$V177,863835026871173,AAA,35,34.516428,10.470160,170915154043,A,9,12,68,74,0.9,9,1988259,525882,605|2|008C|0007B5A6,0200,0003|0000|0000|01A6|0571,00000001,,3,0000,06FB2E,360,511*74"));
+
verifyPosition(decoder, buffer(
"$$V177,863835026871173,AAA,35,34.516428,10.470160,170915154043,A,9,12,68,74,0.9,9,1988259,525882,605|2|008C|0007B5A6,0200,0003|0000|0000|01A6|0571,00000001,,3,0000,010A92,360,511*74"));
diff --git a/test/org/traccar/protocol/TotemProtocolDecoderTest.java b/test/org/traccar/protocol/TotemProtocolDecoderTest.java
index 40d8d9eba..67c75e08d 100644
--- a/test/org/traccar/protocol/TotemProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/TotemProtocolDecoderTest.java
@@ -11,6 +11,12 @@ public class TotemProtocolDecoderTest extends ProtocolTest {
TotemProtocolDecoder decoder = new TotemProtocolDecoder(new TotemProtocol());
verifyPosition(decoder, text(
+ "$$0108AB863835028447675|5004C0001710250234064214059828A058AE121010604000.600000320304.7772N10134.8238E11625B"));
+
+ verifyPosition(decoder, text(
+ "$$0108AA863835028447675|5004C0001710250234134114057728A058AE112108305100.600000660304.7787N10134.8719E116458"));
+
+ verifyPosition(decoder, text(
"$$0112AA864244026065291|180018001409160205244011000027BA0E57063100000001.200000002237.8119N11403.5075E05202D"));
verifyPosition(decoder, text(
diff --git a/test/org/traccar/protocol/WatchFrameDecoderTest.java b/test/org/traccar/protocol/WatchFrameDecoderTest.java
index c705b24b3..664501a43 100644
--- a/test/org/traccar/protocol/WatchFrameDecoderTest.java
+++ b/test/org/traccar/protocol/WatchFrameDecoderTest.java
@@ -1,6 +1,5 @@
package org.traccar.protocol;
-import org.junit.Assert;
import org.junit.Test;
import org.traccar.ProtocolTest;
@@ -11,11 +10,11 @@ public class WatchFrameDecoderTest extends ProtocolTest {
WatchFrameDecoder decoder = new WatchFrameDecoder();
- Assert.assertEquals(
+ verifyFrame(
binary("5b33472a383330383430363237392a303030382a72636170747572655d"),
decoder.decode(null, null, binary("5b33472a383330383430363237392a303030382a72636170747572655d")));
- Assert.assertEquals(
+ verifyFrame(
binary("5b33472a383330383430363237392a303030392a4c4b2c302c302c38345d"),
decoder.decode(null, null, binary("5b33472a383330383430363237392a303030392a4c4b2c302c302c38345d")));