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/DmtHttpProtocolDecoder.java16
-rw-r--r--src/org/traccar/protocol/EelinkProtocol.java13
-rw-r--r--src/org/traccar/protocol/EelinkProtocolDecoder.java95
-rw-r--r--src/org/traccar/protocol/EelinkProtocolEncoder.java65
-rw-r--r--src/org/traccar/protocol/FlespiProtocolDecoder.java20
-rw-r--r--src/org/traccar/protocol/GoSafeProtocolDecoder.java16
-rw-r--r--src/org/traccar/protocol/Gt06ProtocolDecoder.java178
-rw-r--r--src/org/traccar/protocol/Jt600FrameDecoder.java4
-rw-r--r--src/org/traccar/protocol/Jt600ProtocolDecoder.java8
-rw-r--r--src/org/traccar/protocol/MiniFinderProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/OsmAndProtocolDecoder.java16
-rw-r--r--src/org/traccar/protocol/OwnTracksProtocolDecoder.java25
-rw-r--r--src/org/traccar/protocol/Pt502ProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/SigfoxProtocol.java47
-rw-r--r--src/org/traccar/protocol/SigfoxProtocolDecoder.java91
-rw-r--r--src/org/traccar/protocol/TmgFrameDecoder.java67
-rw-r--r--src/org/traccar/protocol/TmgProtocol.java3
-rw-r--r--src/org/traccar/protocol/TmgProtocolDecoder.java83
18 files changed, 587 insertions, 164 deletions
diff --git a/src/org/traccar/protocol/DmtHttpProtocolDecoder.java b/src/org/traccar/protocol/DmtHttpProtocolDecoder.java
index 1bd808a1f..dbcc7a6f8 100644
--- a/src/org/traccar/protocol/DmtHttpProtocolDecoder.java
+++ b/src/org/traccar/protocol/DmtHttpProtocolDecoder.java
@@ -16,13 +16,9 @@
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.HttpHeaders;
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.traccar.BaseProtocolDecoder;
+import org.traccar.BaseHttpProtocolDecoder;
import org.traccar.DeviceSession;
import org.traccar.helper.BitUtil;
import org.traccar.helper.UnitsConverter;
@@ -40,20 +36,12 @@ import java.util.LinkedList;
import java.util.List;
import java.util.TimeZone;
-public class DmtHttpProtocolDecoder extends BaseProtocolDecoder {
+public class DmtHttpProtocolDecoder extends BaseHttpProtocolDecoder {
public DmtHttpProtocolDecoder(DmtHttpProtocol protocol) {
super(protocol);
}
- 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);
- }
- }
-
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
diff --git a/src/org/traccar/protocol/EelinkProtocol.java b/src/org/traccar/protocol/EelinkProtocol.java
index 5499094d9..3d0a006de 100644
--- a/src/org/traccar/protocol/EelinkProtocol.java
+++ b/src/org/traccar/protocol/EelinkProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -15,6 +15,7 @@
*/
package org.traccar.protocol;
+import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder;
@@ -30,6 +31,7 @@ public class EelinkProtocol extends BaseProtocol {
super("eelink");
setSupportedDataCommands(
Command.TYPE_CUSTOM,
+ Command.TYPE_POSITION_SINGLE,
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME,
Command.TYPE_REBOOT_DEVICE);
@@ -41,7 +43,14 @@ public class EelinkProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 3, 2));
- pipeline.addLast("objectEncoder", new EelinkProtocolEncoder());
+ pipeline.addLast("objectEncoder", new EelinkProtocolEncoder(false));
+ pipeline.addLast("objectDecoder", new EelinkProtocolDecoder(EelinkProtocol.this));
+ }
+ });
+ serverList.add(new TrackerServer(new ConnectionlessBootstrap(), getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("objectEncoder", new EelinkProtocolEncoder(true));
pipeline.addLast("objectDecoder", new EelinkProtocolDecoder(EelinkProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/EelinkProtocolDecoder.java b/src/org/traccar/protocol/EelinkProtocolDecoder.java
index 8d0f8016a..98a9f7d6d 100644
--- a/src/org/traccar/protocol/EelinkProtocolDecoder.java
+++ b/src/org/traccar/protocol/EelinkProtocolDecoder.java
@@ -18,16 +18,21 @@ package org.traccar.protocol;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.socket.DatagramChannel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
import org.traccar.helper.BitUtil;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
import org.traccar.model.Position;
import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
import java.util.Date;
+import java.util.regex.Pattern;
public class EelinkProtocolDecoder extends BaseProtocolDecoder {
@@ -55,14 +60,10 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_CAMERA_INFO = 0x1E;
public static final int MSG_CAMERA_DATA = 0x1F;
- private void sendResponse(Channel channel, int type, int index) {
+ private void sendResponse(Channel channel, SocketAddress remoteAddress, String uniqueId, int type, int index) {
if (channel != null) {
- ChannelBuffer response = ChannelBuffers.buffer(7);
- response.writeByte(0x67); response.writeByte(0x67); // header
- response.writeByte(type);
- response.writeShort(2); // length
- response.writeShort(index);
- channel.write(response);
+ channel.write(EelinkProtocolEncoder.encodeContent(
+ channel instanceof DatagramChannel, uniqueId, type, index, null), remoteAddress);
}
}
@@ -189,6 +190,8 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort()));
position.setCourse(buf.readUnsignedShort());
position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ } else {
+ getLastLocation(position, position.getDeviceTime());
}
if (BitUtil.check(flags, 1)) {
@@ -259,36 +262,104 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("Lat:")
+ .number("([NS])(d+.d+)") // latitude
+ .any()
+ .text("Lon:")
+ .number("([EW])(d+.d+)") // longitude
+ .any()
+ .text("Course:")
+ .number("(d+.d+)") // course
+ .any()
+ .text("Speed:")
+ .number("(d+.d+)") // speed
+ .any()
+ .expression("Date ?Time:")
+ .number("(dddd)-(dd)-(dd) ") // date
+ .number("(dd):(dd):(dd)") // time
+ .compile();
+
+ private Position decodeResult(DeviceSession deviceSession, ChannelBuffer buf, int index) {
+
+ Position position = new Position();
+ position.setDeviceId(deviceSession.getDeviceId());
+ position.setProtocol(getProtocolName());
+
+ position.set(Position.KEY_INDEX, index);
+
+ buf.readUnsignedByte(); // type
+ buf.readUnsignedInt(); // uid
+
+ String sentence = buf.toString(StandardCharsets.UTF_8);
+
+ Parser parser = new Parser(PATTERN, sentence);
+ if (parser.matches()) {
+
+ position.setValid(true);
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG));
+ position.setCourse(parser.nextDouble());
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setTime(parser.nextDateTime());
+
+ } else {
+
+ getLastLocation(position, null);
+
+ position.set(Position.KEY_RESULT, sentence);
+
+ }
+
+ return position;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
+ String uniqueId = null;
+ DeviceSession deviceSession;
+
+ if (buf.getByte(0) == 'E' && buf.getByte(1) == 'L') {
+ buf.skipBytes(2 + 2 + 2); // udp header
+ uniqueId = ChannelBuffers.hexDump(buf.readBytes(8)).substring(1);
+ deviceSession = getDeviceSession(channel, remoteAddress, uniqueId);
+ } else {
+ deviceSession = getDeviceSession(channel, remoteAddress);
+ }
+
buf.skipBytes(2); // header
int type = buf.readUnsignedByte();
buf.readShort(); // length
int index = buf.readUnsignedShort();
if (type != MSG_GPS && type != MSG_DATA) {
- sendResponse(channel, type, index);
+ sendResponse(channel, remoteAddress, uniqueId, type, index);
}
if (type == MSG_LOGIN) {
- getDeviceSession(channel, remoteAddress, ChannelBuffers.hexDump(buf.readBytes(8)).substring(1));
+ if (deviceSession == null) {
+ getDeviceSession(channel, remoteAddress, ChannelBuffers.hexDump(buf.readBytes(8)).substring(1));
+ }
} else {
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
if (deviceSession == null) {
return null;
}
if (type == MSG_GPS || type == MSG_ALARM || type == MSG_STATE || type == MSG_SMS) {
+
return decodeOld(deviceSession, buf, type, index);
+
} else if (type >= MSG_NORMAL && type <= MSG_OBD_CODE) {
+
return decodeNew(deviceSession, buf, index);
+
} else if (type == MSG_HEARTBEAT && buf.readableBytes() >= 2) {
Position position = new Position();
@@ -301,6 +372,10 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
return position;
+ } else if (type == MSG_DOWNLINK) {
+
+ return decodeResult(deviceSession, buf, index);
+
}
}
diff --git a/src/org/traccar/protocol/EelinkProtocolEncoder.java b/src/org/traccar/protocol/EelinkProtocolEncoder.java
index 5a28733f7..76865a039 100644
--- a/src/org/traccar/protocol/EelinkProtocolEncoder.java
+++ b/src/org/traccar/protocol/EelinkProtocolEncoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -21,25 +21,68 @@ import org.traccar.BaseProtocolEncoder;
import org.traccar.helper.Log;
import org.traccar.model.Command;
+import javax.xml.bind.DatatypeConverter;
+import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
public class EelinkProtocolEncoder extends BaseProtocolEncoder {
- private ChannelBuffer encodeContent(String content) {
+ private boolean connectionless;
+
+ public EelinkProtocolEncoder(boolean connectionless) {
+ this.connectionless = connectionless;
+ }
+
+ public static int checksum(ByteBuffer buf) {
+ int sum = 0;
+ while (buf.hasRemaining()) {
+ sum = (((sum << 1) | (sum >> 15)) + (buf.get() & 0xFF)) & 0xFFFF;
+ }
+ return sum;
+ }
+
+ public static ChannelBuffer encodeContent(
+ boolean connectionless, String uniqueId, int type, int index, ChannelBuffer content) {
ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
+ if (connectionless) {
+ buf.writeBytes(ChannelBuffers.wrappedBuffer(DatatypeConverter.parseHexBinary('0' + uniqueId)));
+ }
+
buf.writeByte(0x67);
buf.writeByte(0x67);
- buf.writeByte(EelinkProtocolDecoder.MSG_DOWNLINK);
- buf.writeShort(2 + 1 + 4 + content.length()); // length
- buf.writeShort(0); // index
+ buf.writeByte(type);
+ buf.writeShort(2 + (content != null ? content.readableBytes() : 0)); // length
+ buf.writeShort(index);
+
+ if (content != null) {
+ buf.writeBytes(content);
+ }
+
+ ChannelBuffer result = ChannelBuffers.dynamicBuffer();
+
+ if (connectionless) {
+ result.writeByte('E');
+ result.writeByte('L');
+ result.writeShort(2 + buf.readableBytes()); // length
+ result.writeShort(checksum(buf.toByteBuffer()));
+ }
+
+ result.writeBytes(buf);
+
+ return result;
+ }
+
+ private ChannelBuffer encodeContent(long deviceId, String content) {
+
+ ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
buf.writeByte(0x01); // command
buf.writeInt(0); // server id
buf.writeBytes(content.getBytes(StandardCharsets.UTF_8));
- return buf;
+ return encodeContent(connectionless, getUniqueId(deviceId), EelinkProtocolDecoder.MSG_DOWNLINK, 0, buf);
}
@Override
@@ -47,13 +90,15 @@ public class EelinkProtocolEncoder extends BaseProtocolEncoder {
switch (command.getType()) {
case Command.TYPE_CUSTOM:
- return encodeContent(command.getString(Command.KEY_DATA));
+ return encodeContent(command.getDeviceId(), command.getString(Command.KEY_DATA));
+ case Command.TYPE_POSITION_SINGLE:
+ return encodeContent(command.getDeviceId(), "WHERE#");
case Command.TYPE_ENGINE_STOP:
- return encodeContent("RELAY,1#");
+ return encodeContent(command.getDeviceId(), "RELAY,1#");
case Command.TYPE_ENGINE_RESUME:
- return encodeContent("RELAY,0#");
+ return encodeContent(command.getDeviceId(), "RELAY,0#");
case Command.TYPE_REBOOT_DEVICE:
- return encodeContent("RESET#");
+ return encodeContent(command.getDeviceId(), "RESET#");
default:
Log.warning(new UnsupportedOperationException(command.getType()));
break;
diff --git a/src/org/traccar/protocol/FlespiProtocolDecoder.java b/src/org/traccar/protocol/FlespiProtocolDecoder.java
index 799d78ecb..d122df383 100644
--- a/src/org/traccar/protocol/FlespiProtocolDecoder.java
+++ b/src/org/traccar/protocol/FlespiProtocolDecoder.java
@@ -16,13 +16,9 @@
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.BaseHttpProtocolDecoder;
import org.traccar.DeviceSession;
import org.traccar.model.Position;
@@ -34,11 +30,11 @@ 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;
+import java.util.LinkedList;
+import java.util.List;
-public class FlespiProtocolDecoder extends BaseProtocolDecoder {
+public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder {
public FlespiProtocolDecoder(FlespiProtocol protocol) {
super(protocol);
@@ -72,14 +68,6 @@ public class FlespiProtocolDecoder extends BaseProtocolDecoder {
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());
diff --git a/src/org/traccar/protocol/GoSafeProtocolDecoder.java b/src/org/traccar/protocol/GoSafeProtocolDecoder.java
index f9aaae0ce..62f6212e2 100644
--- a/src/org/traccar/protocol/GoSafeProtocolDecoder.java
+++ b/src/org/traccar/protocol/GoSafeProtocolDecoder.java
@@ -168,10 +168,18 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_BATTERY, parser.nextDouble());
if (parser.hasNext(6)) {
- long status = parser.nextLong(16, 0);
- position.set(Position.KEY_IGNITION, BitUtil.check(status, 13));
- position.set(Position.KEY_STATUS, status);
- position.set("ioStatus", parser.next());
+ position.set(Position.KEY_STATUS, parser.nextHexLong());
+ Integer io = parser.nextHexInt();
+ if (io != null) {
+ position.set(Position.KEY_IGNITION, BitUtil.check(io, 0));
+ position.set(Position.PREFIX_IN + 1, BitUtil.check(io, 1));
+ position.set(Position.PREFIX_IN + 2, BitUtil.check(io, 2));
+ position.set(Position.PREFIX_IN + 3, BitUtil.check(io, 3));
+ position.set(Position.PREFIX_IN + 4, BitUtil.check(io, 4));
+ position.set(Position.PREFIX_OUT + 1, BitUtil.check(io, 5));
+ position.set(Position.PREFIX_OUT + 2, BitUtil.check(io, 6));
+ position.set(Position.PREFIX_OUT + 3, BitUtil.check(io, 7));
+ }
position.set(Position.KEY_GEOFENCE, parser.next() + parser.next());
position.set("eventStatus", parser.next());
position.set("packetType", parser.next());
diff --git a/src/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/org/traccar/protocol/Gt06ProtocolDecoder.java
index 177c0b653..2018fb6a6 100644
--- a/src/org/traccar/protocol/Gt06ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gt06ProtocolDecoder.java
@@ -36,6 +36,7 @@ import org.traccar.model.WifiAccessPoint;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
+import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
@@ -78,6 +79,9 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_LBS_STATUS = 0x19;
public static final int MSG_GPS_PHONE = 0x1A;
public static final int MSG_GPS_LBS_EXTEND = 0x1E;
+ public static final int MSG_HEARTBEAT = 0x23;
+ public static final int MSG_ADDRESS_REQUEST = 0x2A;
+ public static final int MSG_ADDRESS_RESPONSE = 0x97;
public static final int MSG_AZ735_GPS = 0x32;
public static final int MSG_AZ735_ALARM = 0x33;
public static final int MSG_X1_GPS = 0x34;
@@ -87,27 +91,69 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_COMMAND_0 = 0x80;
public static final int MSG_COMMAND_1 = 0x81;
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_STRING_INFO = 0x21;
+ public static final int MSG_GPS_2 = 0xA0;
+ public static final int MSG_LBS_2 = 0xA1;
+ public static final int MSG_WIFI_3 = 0xA2;
+ public static final int MSG_FENCE_SINGLE = 0xA3;
+ public static final int MSG_FENCE_MULTI = 0xA4;
+ public static final int MSG_LBS_ALARM = 0xA5;
+ public static final int MSG_LBS_ADDRESS = 0xA7;
private static boolean isSupported(int type) {
return hasGps(type) || hasLbs(type) || hasStatus(type);
}
private static boolean hasGps(int type) {
- return type == MSG_GPS || type == MSG_GPS_LBS_1 || type == MSG_GPS_LBS_2
- || type == MSG_GPS_LBS_STATUS_1 || type == MSG_GPS_LBS_STATUS_2 || type == MSG_GPS_LBS_STATUS_3
- || type == MSG_GPS_PHONE || type == MSG_GPS_LBS_EXTEND;
+ switch (type) {
+ case MSG_GPS:
+ case MSG_GPS_LBS_1:
+ case MSG_GPS_LBS_2:
+ case MSG_GPS_LBS_STATUS_1:
+ case MSG_GPS_LBS_STATUS_2:
+ case MSG_GPS_LBS_STATUS_3:
+ case MSG_GPS_PHONE:
+ case MSG_GPS_LBS_EXTEND:
+ case MSG_GPS_2:
+ case MSG_FENCE_SINGLE:
+ return true;
+ default:
+ return false;
+ }
}
private static boolean hasLbs(int type) {
- return type == MSG_LBS || type == MSG_LBS_STATUS || type == MSG_GPS_LBS_1 || type == MSG_GPS_LBS_2
- || type == MSG_GPS_LBS_STATUS_1 || type == MSG_GPS_LBS_STATUS_2 || type == MSG_GPS_LBS_STATUS_3;
+ switch (type) {
+ case MSG_LBS:
+ case MSG_LBS_STATUS:
+ case MSG_GPS_LBS_1:
+ case MSG_GPS_LBS_2:
+ case MSG_GPS_LBS_STATUS_1:
+ case MSG_GPS_LBS_STATUS_2:
+ case MSG_GPS_LBS_STATUS_3:
+ case MSG_GPS_2:
+ case MSG_FENCE_SINGLE:
+ case MSG_LBS_ALARM:
+ case MSG_LBS_ADDRESS:
+ return true;
+ default:
+ return false;
+ }
}
private static boolean hasStatus(int type) {
- return type == MSG_STATUS || type == MSG_LBS_STATUS
- || type == MSG_GPS_LBS_STATUS_1 || type == MSG_GPS_LBS_STATUS_2 || type == MSG_GPS_LBS_STATUS_3;
+ switch (type) {
+ case MSG_STATUS:
+ case MSG_LBS_STATUS:
+ case MSG_GPS_LBS_STATUS_1:
+ case MSG_GPS_LBS_STATUS_2:
+ case MSG_GPS_LBS_STATUS_3:
+ return true;
+ default:
+ return false;
+ }
}
private void sendResponse(Channel channel, boolean extended, int type, ChannelBuffer content) {
@@ -348,6 +394,44 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
sendResponse(channel, false, type, null);
}
+ } else if (type == MSG_HEARTBEAT) {
+
+ Position position = new Position();
+ position.setDeviceId(deviceSession.getDeviceId());
+ position.setProtocol(getProtocolName());
+
+ getLastLocation(position, null);
+
+ int status = buf.readUnsignedByte();
+ position.set(Position.KEY_ARMED, BitUtil.check(status, 0));
+ position.set(Position.KEY_IGNITION, BitUtil.check(status, 1));
+ position.set(Position.KEY_CHARGE, BitUtil.check(status, 2));
+
+ sendResponse(channel, false, type, null);
+
+ return position;
+
+ } else if (type == MSG_ADDRESS_REQUEST) {
+
+ String response = "NA&&NA&&0##";
+ ChannelBuffer content = ChannelBuffers.dynamicBuffer();
+ content.writeByte(response.length());
+ content.writeInt(0);
+ content.writeBytes(response.getBytes(StandardCharsets.US_ASCII));
+ sendResponse(channel, true, MSG_ADDRESS_RESPONSE, content);
+
+ } else if (type == MSG_TIME_REQUEST) {
+
+ Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ ChannelBuffer content = ChannelBuffers.dynamicBuffer();
+ content.writeByte(calendar.get(Calendar.YEAR) - 2000);
+ content.writeByte(calendar.get(Calendar.MONTH) + 1);
+ content.writeByte(calendar.get(Calendar.DAY_OF_MONTH));
+ content.writeByte(calendar.get(Calendar.HOUR_OF_DAY));
+ content.writeByte(calendar.get(Calendar.MINUTE));
+ content.writeByte(calendar.get(Calendar.SECOND));
+ sendResponse(channel, false, MSG_TIME_REQUEST, content);
+
} else if (type == MSG_X1_GPS) {
Position position = new Position();
@@ -385,48 +469,53 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
} else if (type == MSG_WIFI || type == MSG_WIFI_2) {
- Position position = new Position();
- position.setDeviceId(deviceSession.getDeviceId());
- position.setProtocol(getProtocolName());
-
- DateBuilder dateBuilder = new DateBuilder()
- .setYear(BcdUtil.readInteger(buf, 2))
- .setMonth(BcdUtil.readInteger(buf, 2))
- .setDay(BcdUtil.readInteger(buf, 2))
- .setHour(BcdUtil.readInteger(buf, 2))
- .setMinute(BcdUtil.readInteger(buf, 2))
- .setSecond(BcdUtil.readInteger(buf, 2));
- getLastLocation(position, dateBuilder.getDate());
+ return decodeWifi(buf, deviceSession);
- Network network = new Network();
+ } else {
- int wifiCount = buf.getByte(2);
- for (int i = 0; i < wifiCount; i++) {
- String mac = String.format("%02x:%02x:%02x:%02x:%02x:%02x",
- buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte(),
- buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
- network.addWifiAccessPoint(WifiAccessPoint.from(mac, buf.readUnsignedByte()));
- }
+ return decodeBasicOther(channel, buf, deviceSession, type, dataLength);
- int cellCount = buf.readUnsignedByte();
- int mcc = buf.readUnsignedShort();
- int mnc = buf.readUnsignedByte();
- for (int i = 0; i < cellCount; i++) {
- network.addCellTower(CellTower.from(
- mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedByte()));
- }
+ }
- position.setNetwork(network);
+ return null;
+ }
- return position;
+ private Object decodeWifi(ChannelBuffer buf, DeviceSession deviceSession) throws Exception {
- } else {
+ Position position = new Position();
+ position.setDeviceId(deviceSession.getDeviceId());
+ position.setProtocol(getProtocolName());
- return decodeBasicOther(channel, buf, deviceSession, type, dataLength);
+ DateBuilder dateBuilder = new DateBuilder()
+ .setYear(BcdUtil.readInteger(buf, 2))
+ .setMonth(BcdUtil.readInteger(buf, 2))
+ .setDay(BcdUtil.readInteger(buf, 2))
+ .setHour(BcdUtil.readInteger(buf, 2))
+ .setMinute(BcdUtil.readInteger(buf, 2))
+ .setSecond(BcdUtil.readInteger(buf, 2));
+ getLastLocation(position, dateBuilder.getDate());
+
+ Network network = new Network();
+
+ int wifiCount = buf.getByte(2);
+ for (int i = 0; i < wifiCount; i++) {
+ String mac = String.format("%02x:%02x:%02x:%02x:%02x:%02x",
+ buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte(),
+ buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ network.addWifiAccessPoint(WifiAccessPoint.from(mac, buf.readUnsignedByte()));
+ }
+ int cellCount = buf.readUnsignedByte();
+ int mcc = buf.readUnsignedShort();
+ int mnc = buf.readUnsignedByte();
+ for (int i = 0; i < cellCount; i++) {
+ network.addCellTower(CellTower.from(
+ mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedByte()));
}
- return null;
+ position.setNetwork(network);
+
+ return position;
}
private Object decodeBasicOther(Channel channel, ChannelBuffer buf,
@@ -436,7 +525,10 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
position.setDeviceId(deviceSession.getDeviceId());
position.setProtocol(getProtocolName());
- if (type == MSG_LBS_MULTIPLE || type == MSG_LBS_EXTEND || type == MSG_LBS_WIFI) {
+ if (type == MSG_LBS_MULTIPLE || type == MSG_LBS_EXTEND || type == MSG_LBS_WIFI
+ || type == MSG_LBS_2 || type == MSG_WIFI_3) {
+
+ boolean longFormat = type == MSG_LBS_2 || type == MSG_WIFI_3;
DateBuilder dateBuilder = new DateBuilder(timeZone)
.setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
@@ -448,8 +540,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
int mnc = buf.readUnsignedByte();
Network network = new Network();
for (int i = 0; i < 7; i++) {
- int lac = buf.readUnsignedShort();
- int cid = buf.readUnsignedMedium();
+ int lac = longFormat ? buf.readInt() : buf.readUnsignedShort();
+ int cid = longFormat ? (int) buf.readLong() : buf.readUnsignedMedium();
int rssi = -buf.readUnsignedByte();
if (lac > 0) {
network.addCellTower(CellTower.from(mcc, mnc, lac, cid, rssi));
@@ -458,7 +550,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedByte(); // time leads
- if (type != MSG_LBS_MULTIPLE) {
+ if (type != MSG_LBS_MULTIPLE && type != MSG_LBS_2) {
int wifiCount = buf.readUnsignedByte();
for (int i = 0; i < wifiCount; i++) {
String mac = ChannelBuffers.hexDump(buf.readBytes(6)).replaceAll("(..)", "$1:");
diff --git a/src/org/traccar/protocol/Jt600FrameDecoder.java b/src/org/traccar/protocol/Jt600FrameDecoder.java
index 5606ae1fc..261f46fe8 100644
--- a/src/org/traccar/protocol/Jt600FrameDecoder.java
+++ b/src/org/traccar/protocol/Jt600FrameDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 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.
@@ -37,7 +37,7 @@ public class Jt600FrameDecoder extends FrameDecoder {
if (type == '$') {
boolean longFormat = buf.getUnsignedByte(buf.readerIndex() + 1) == 0x75;
int length = buf.getUnsignedShort(buf.readerIndex() + (longFormat ? 8 : 7)) + 10;
- if (length >= buf.readableBytes()) {
+ if (length <= buf.readableBytes()) {
return buf.readBytes(length);
}
} else if (type == '(') {
diff --git a/src/org/traccar/protocol/Jt600ProtocolDecoder.java b/src/org/traccar/protocol/Jt600ProtocolDecoder.java
index 58835c7d6..e935c1449 100644
--- a/src/org/traccar/protocol/Jt600ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Jt600ProtocolDecoder.java
@@ -63,8 +63,9 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
return null;
}
+ int protocolVersion = 0;
if (longFormat) {
- buf.readUnsignedByte(); // protocol
+ protocolVersion = buf.readUnsignedByte();
}
int version = BitUtil.from(buf.readUnsignedByte(), 4);
@@ -122,6 +123,11 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
cellTower.setSignalStrength((int) buf.readUnsignedByte());
position.setNetwork(new Network(cellTower));
+ if (protocolVersion == 0x17) {
+ buf.readUnsignedByte(); // geofence id
+ buf.skipBytes(3); // reserved
+ }
+
} else if (version == 1) {
position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
diff --git a/src/org/traccar/protocol/MiniFinderProtocolDecoder.java b/src/org/traccar/protocol/MiniFinderProtocolDecoder.java
index 05994b697..8e6e56e80 100644
--- a/src/org/traccar/protocol/MiniFinderProtocolDecoder.java
+++ b/src/org/traccar/protocol/MiniFinderProtocolDecoder.java
@@ -123,7 +123,7 @@ public class MiniFinderProtocolDecoder extends BaseProtocolDecoder {
position.setAltitude(parser.nextDouble(0));
- position.set(Position.KEY_BATTERY, parser.nextInt(0));
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0));
}
@Override
diff --git a/src/org/traccar/protocol/OsmAndProtocolDecoder.java b/src/org/traccar/protocol/OsmAndProtocolDecoder.java
index 15a71c88b..68c143257 100644
--- a/src/org/traccar/protocol/OsmAndProtocolDecoder.java
+++ b/src/org/traccar/protocol/OsmAndProtocolDecoder.java
@@ -16,15 +16,11 @@
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.HttpHeaders;
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.QueryStringDecoder;
import org.joda.time.format.ISODateTimeFormat;
-import org.traccar.BaseProtocolDecoder;
+import org.traccar.BaseHttpProtocolDecoder;
import org.traccar.DeviceSession;
import org.traccar.model.Position;
@@ -36,20 +32,12 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
-public class OsmAndProtocolDecoder extends BaseProtocolDecoder {
+public class OsmAndProtocolDecoder extends BaseHttpProtocolDecoder {
public OsmAndProtocolDecoder(OsmAndProtocol protocol) {
super(protocol);
}
- 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);
- }
- }
-
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
diff --git a/src/org/traccar/protocol/OwnTracksProtocolDecoder.java b/src/org/traccar/protocol/OwnTracksProtocolDecoder.java
index f3284d9e2..49d1cff96 100644
--- a/src/org/traccar/protocol/OwnTracksProtocolDecoder.java
+++ b/src/org/traccar/protocol/OwnTracksProtocolDecoder.java
@@ -17,39 +17,26 @@
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.HttpHeaders;
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.traccar.BaseProtocolDecoder;
+import org.traccar.BaseHttpProtocolDecoder;
import org.traccar.DeviceSession;
-import org.traccar.model.Position;
import org.traccar.helper.UnitsConverter;
+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;
-import java.io.StringReader;
-import javax.json.Json;
-import javax.json.JsonObject;
-
-public class OwnTracksProtocolDecoder extends BaseProtocolDecoder {
+public class OwnTracksProtocolDecoder extends BaseHttpProtocolDecoder {
public OwnTracksProtocolDecoder(OwnTracksProtocol protocol) {
super(protocol);
}
- 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);
- }
- }
-
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
diff --git a/src/org/traccar/protocol/Pt502ProtocolDecoder.java b/src/org/traccar/protocol/Pt502ProtocolDecoder.java
index 1d976dcd5..330ba7643 100644
--- a/src/org/traccar/protocol/Pt502ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Pt502ProtocolDecoder.java
@@ -78,6 +78,8 @@ public class Pt502ProtocolDecoder extends BaseProtocolDecoder {
return Position.ALARM_VIBRATION;
case "PMA":
return Position.ALARM_MOVEMENT;
+ case "CPA":
+ return Position.ALARM_POWER_CUT;
default:
return null;
}
diff --git a/src/org/traccar/protocol/SigfoxProtocol.java b/src/org/traccar/protocol/SigfoxProtocol.java
new file mode 100644
index 000000000..9feaea12d
--- /dev/null
+++ b/src/org/traccar/protocol/SigfoxProtocol.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.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 SigfoxProtocol extends BaseProtocol {
+
+ public SigfoxProtocol() {
+ super("sigfox");
+ }
+
+ @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(65535));
+ pipeline.addLast("objectDecoder", new SigfoxProtocolDecoder(SigfoxProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/org/traccar/protocol/SigfoxProtocolDecoder.java
new file mode 100644
index 000000000..7cf57681f
--- /dev/null
+++ b/src/org/traccar/protocol/SigfoxProtocolDecoder.java
@@ -0,0 +1,91 @@
+/*
+ * 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.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.handler.codec.http.HttpRequest;
+import org.jboss.netty.handler.codec.http.HttpResponseStatus;
+import org.traccar.BaseHttpProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.xml.bind.DatatypeConverter;
+import java.io.StringReader;
+import java.net.SocketAddress;
+import java.net.URLDecoder;
+import java.nio.ByteOrder;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+
+public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder {
+
+ public SigfoxProtocolDecoder(SigfoxProtocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ HttpRequest request = (HttpRequest) msg;
+ JsonObject json = Json.createReader(new StringReader(URLDecoder.decode(
+ request.getContent().toString(StandardCharsets.UTF_8).split("=")[0], "UTF-8"))).readObject();
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, json.getString("device"));
+ if (deviceSession == null) {
+ sendResponse(channel, HttpResponseStatus.BAD_REQUEST);
+ return null;
+ }
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setTime(new Date(json.getInt("time") * 1000L));
+
+ ChannelBuffer buf = ChannelBuffers.wrappedBuffer(
+ ByteOrder.LITTLE_ENDIAN, DatatypeConverter.parseHexBinary(json.getString("data")));
+
+ int type = buf.readUnsignedByte() >> 4;
+ if (type == 0) {
+
+ position.setValid(true);
+ position.setLatitude(buf.readInt() * 0.0000001);
+ position.setLongitude(buf.readInt() * 0.0000001);
+ position.setCourse(buf.readUnsignedByte() * 2);
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
+
+ position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.025);
+
+ } else {
+
+ getLastLocation(position, position.getDeviceTime());
+
+ }
+
+ position.set(Position.KEY_RSSI, json.getJsonNumber("rssi").doubleValue());
+ position.set(Position.KEY_INDEX, json.getInt("seqNumber"));
+
+ sendResponse(channel, HttpResponseStatus.OK);
+ return position;
+ }
+
+}
diff --git a/src/org/traccar/protocol/TmgFrameDecoder.java b/src/org/traccar/protocol/TmgFrameDecoder.java
new file mode 100644
index 000000000..549c42466
--- /dev/null
+++ b/src/org/traccar/protocol/TmgFrameDecoder.java
@@ -0,0 +1,67 @@
+/*
+ * 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.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBufferIndexFinder;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.frame.FrameDecoder;
+
+public class TmgFrameDecoder extends FrameDecoder {
+
+ private boolean isLetter(byte c) {
+ return c >= 'a' && c <= 'z';
+ }
+
+ @Override
+ protected Object decode(
+ ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception {
+
+ int beginIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), new ChannelBufferIndexFinder() {
+ @Override
+ public boolean find(ChannelBuffer buffer, int guessedIndex) {
+ if (buffer.getByte(guessedIndex) != (byte) '$' || buffer.writerIndex() - guessedIndex < 5) {
+ return false;
+ }
+ if (buffer.getByte(guessedIndex + 4) == ','
+ && isLetter(buffer.getByte(guessedIndex + 1))
+ && isLetter(buffer.getByte(guessedIndex + 2))
+ && isLetter(buffer.getByte(guessedIndex + 3))) {
+ return true;
+ }
+ return false;
+ }
+ });
+
+ if (beginIndex >= 0) {
+
+ buf.readerIndex(beginIndex);
+
+ int endIndex = buf.indexOf(beginIndex, buf.writerIndex(), (byte) '\n');
+
+ if (endIndex >= 0) {
+ ChannelBuffer frame = buf.readBytes(endIndex - beginIndex);
+ buf.readByte(); // delimiter
+ return frame;
+ }
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/protocol/TmgProtocol.java b/src/org/traccar/protocol/TmgProtocol.java
index f30d61e9a..c11762cac 100644
--- a/src/org/traccar/protocol/TmgProtocol.java
+++ b/src/org/traccar/protocol/TmgProtocol.java
@@ -17,7 +17,6 @@ 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;
@@ -36,7 +35,7 @@ public class TmgProtocol extends BaseProtocol {
serverList.add(new TrackerServer(new ServerBootstrap(), getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
+ pipeline.addLast("frameDecoder", new TmgFrameDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new TmgProtocolDecoder(TmgProtocol.this));
diff --git a/src/org/traccar/protocol/TmgProtocolDecoder.java b/src/org/traccar/protocol/TmgProtocolDecoder.java
index b8458dd52..5e852aff2 100644
--- a/src/org/traccar/protocol/TmgProtocolDecoder.java
+++ b/src/org/traccar/protocol/TmgProtocolDecoder.java
@@ -36,7 +36,7 @@ public class TmgProtocolDecoder extends BaseProtocolDecoder {
private static final Pattern PATTERN = new PatternBuilder()
.text("$")
.expression("(...),") // type
- .expression("[LH],") // history
+ .expression("[LH],").optional() // history
.number("(d+),") // imei
.number("(dd)(dd)(dddd),") // date (ddmmyyyy)
.number("(dd)(dd)(dd),") // time (hhmmss)
@@ -47,6 +47,7 @@ public class TmgProtocolDecoder extends BaseProtocolDecoder {
.expression("([EW]),")
.number("(d+.?d*),") // speed
.number("(d+.?d*),") // course
+ .groupBegin()
.number("(-?d+.?d*),") // altitude
.number("(d+.d+),") // hdop
.number("(d+),") // satellites
@@ -65,6 +66,20 @@ public class TmgProtocolDecoder extends BaseProtocolDecoder {
.number("d+.?d*,") // trip meter
.expression("([^,]*),") // software version
.expression("([^,]*),").optional() // rfid
+ .or()
+ .number("[^,]*,") // cid
+ .number("(d+),") // rssi
+ .number("(d+),") // satellites
+ .number("[^,]*,") // battery level
+ .expression("([01]),") // ignition
+ .expression("[LH]{4},") // input
+ .expression("[NT]{4},") // tamper status
+ .expression("[LH]{2},") // output
+ .number("(d+.d+),") // adc1
+ .number("(d+.d+),") // adc1
+ .number("[^,]*,") // device id
+ .number("(d+),") // odometer
+ .groupEnd()
.any()
.compile();
@@ -115,36 +130,52 @@ public class TmgProtocolDecoder extends BaseProtocolDecoder {
position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
- position.setValid(parser.nextInt(0) > 0);
+ position.setValid(parser.nextInt() > 0);
position.setLatitude(parser.nextCoordinate());
position.setLongitude(parser.nextCoordinate());
- position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0)));
- position.setCourse(parser.nextDouble(0));
- position.setAltitude(parser.nextDouble(0));
-
- position.set(Position.KEY_HDOP, parser.nextDouble(0));
- position.set(Position.KEY_SATELLITES, parser.nextInt(0));
- position.set(Position.KEY_SATELLITES_VISIBLE, parser.nextInt(0));
- position.set(Position.KEY_OPERATOR, parser.next());
- position.set(Position.KEY_RSSI, parser.nextInt(0));
- position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1);
- position.set(Position.KEY_BATTERY, parser.nextDouble(0));
- position.set(Position.KEY_POWER, parser.nextDouble(0));
-
- int input = parser.nextBinInt(0);
- int output = parser.nextBinInt(0);
-
- if (!BitUtil.check(input, 0)) {
- position.set(Position.KEY_ALARM, Position.ALARM_SOS);
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
+
+ if (parser.hasNext(15)) {
+
+ position.setAltitude(parser.nextDouble());
+
+ position.set(Position.KEY_HDOP, parser.nextDouble());
+ position.set(Position.KEY_SATELLITES, parser.nextInt());
+ position.set(Position.KEY_SATELLITES_VISIBLE, parser.nextInt());
+ position.set(Position.KEY_OPERATOR, parser.next());
+ position.set(Position.KEY_RSSI, parser.nextInt());
+ position.set(Position.KEY_IGNITION, parser.nextInt() == 1);
+ position.set(Position.KEY_BATTERY, parser.nextDouble());
+ position.set(Position.KEY_POWER, parser.nextDouble());
+
+ int input = parser.nextBinInt();
+ int output = parser.nextBinInt();
+
+ if (!BitUtil.check(input, 0)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_SOS);
+ }
+
+ position.set(Position.KEY_INPUT, input);
+ position.set(Position.KEY_OUTPUT, output);
+
+ position.set(Position.PREFIX_ADC + 1, parser.nextDouble());
+ position.set(Position.PREFIX_ADC + 2, parser.nextDouble());
+ position.set(Position.KEY_VERSION_FW, parser.next());
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next());
+
}
- position.set(Position.KEY_INPUT, input);
- position.set(Position.KEY_OUTPUT, output);
+ if (parser.hasNext(6)) {
+
+ position.set(Position.KEY_RSSI, parser.nextInt());
+ position.set(Position.KEY_SATELLITES, parser.nextInt());
+ position.set(Position.KEY_IGNITION, parser.nextInt() == 1);
+ position.set(Position.PREFIX_ADC + 1, parser.nextDouble());
+ position.set(Position.PREFIX_ADC + 2, parser.nextDouble());
+ position.set(Position.KEY_ODOMETER, parser.nextInt());
- position.set(Position.PREFIX_ADC + 1, parser.nextDouble(0));
- position.set(Position.PREFIX_ADC + 2, parser.nextDouble(0));
- position.set(Position.KEY_VERSION_FW, parser.next());
- position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next());
+ }
return position;
}