aboutsummaryrefslogtreecommitdiff
path: root/src/org/traccar/protocol
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/traccar/protocol')
-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
7 files changed, 624 insertions, 134 deletions
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;
}
}