aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--setup/default.xml1
-rw-r--r--setup/traccar.iss2
-rw-r--r--src/org/traccar/BaseHttpProtocolDecoder.java39
-rw-r--r--src/org/traccar/Context.java111
-rw-r--r--src/org/traccar/database/DataManager.java2
-rw-r--r--src/org/traccar/database/PermissionsManager.java3
-rw-r--r--src/org/traccar/notification/EventForwarder.java54
-rw-r--r--src/org/traccar/notification/JsonTypeEventForwarder.java20
-rw-r--r--src/org/traccar/notification/MultiPartEventForwarder.java46
-rw-r--r--src/org/traccar/notification/NotificationFormatter.java39
-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
-rw-r--r--test/org/traccar/protocol/EelinkProtocolDecoderTest.java14
-rw-r--r--test/org/traccar/protocol/EelinkProtocolEncoderTest.java6
-rw-r--r--test/org/traccar/protocol/Gt06ProtocolDecoderTest.java30
-rw-r--r--test/org/traccar/protocol/Jt600FrameDecoderTest.java14
-rw-r--r--test/org/traccar/protocol/Jt600ProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/Pt502ProtocolDecoderTest.java12
-rw-r--r--test/org/traccar/protocol/SigfoxProtocolDecoderTest.java19
-rw-r--r--test/org/traccar/protocol/TmgFrameDecoderTest.java24
-rw-r--r--test/org/traccar/protocol/TmgProtocolDecoderTest.java9
37 files changed, 945 insertions, 254 deletions
diff --git a/setup/default.xml b/setup/default.xml
index 3424e8187..ec0ff86d2 100644
--- a/setup/default.xml
+++ b/setup/default.xml
@@ -222,5 +222,6 @@
<entry key='recoda.port'>5151</entry>
<entry key='oko.port'>5152</entry>
<entry key='ivt401.port'>5153</entry>
+ <entry key='sigfox.port'>5154</entry>
</properties>
diff --git a/setup/traccar.iss b/setup/traccar.iss
index 3d6c1a872..c929f6d9e 100644
--- a/setup/traccar.iss
+++ b/setup/traccar.iss
@@ -40,7 +40,7 @@ end;
function InitializeSetup(): Boolean;
begin
- if RegKeyExists(GetLocalMachine(), 'SOFTWARE\JavaSoft\Java Runtime Environment') then
+ if RegKeyExists(GetLocalMachine(), 'SOFTWARE\JavaSoft') then
begin
Result := true;
end
diff --git a/src/org/traccar/BaseHttpProtocolDecoder.java b/src/org/traccar/BaseHttpProtocolDecoder.java
new file mode 100644
index 000000000..934a1b81e
--- /dev/null
+++ b/src/org/traccar/BaseHttpProtocolDecoder.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+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.HttpResponse;
+import org.jboss.netty.handler.codec.http.HttpResponseStatus;
+import org.jboss.netty.handler.codec.http.HttpVersion;
+
+public abstract class BaseHttpProtocolDecoder extends BaseProtocolDecoder {
+
+ public BaseHttpProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ public 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);
+ }
+ }
+
+}
diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java
index 511ec980e..3681cc2cc 100644
--- a/src/org/traccar/Context.java
+++ b/src/org/traccar/Context.java
@@ -71,6 +71,8 @@ import org.traccar.geolocation.GeolocationProvider;
import org.traccar.geolocation.MozillaGeolocationProvider;
import org.traccar.geolocation.OpenCellIdGeolocationProvider;
import org.traccar.notification.EventForwarder;
+import org.traccar.notification.JsonTypeEventForwarder;
+import org.traccar.notification.MultiPartEventForwarder;
import org.traccar.reports.model.TripsConfig;
import org.traccar.smpp.SmppClient;
import org.traccar.web.WebServer;
@@ -323,6 +325,9 @@ public final class Context {
objectMapper = new ObjectMapper();
objectMapper.setConfig(
objectMapper.getSerializationConfig().without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS));
+ if (Context.getConfig().getBoolean("mapper.prettyPrintedJson")) {
+ objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
+ }
if (config.hasKey("database.url")) {
dataManager = new DataManager(config);
@@ -349,24 +354,7 @@ public final class Context {
}
if (config.getBoolean("geolocation.enable")) {
- String type = config.getString("geolocation.type", "mozilla");
- String url = config.getString("geolocation.url");
- String key = config.getString("geolocation.key");
-
- switch (type) {
- case "google":
- geolocationProvider = new GoogleGeolocationProvider(key);
- break;
- case "opencellid":
- geolocationProvider = new OpenCellIdGeolocationProvider(key);
- break;
- case "unwired":
- geolocationProvider = new UnwiredGeolocationProvider(url, key);
- break;
- default:
- geolocationProvider = new MozillaGeolocationProvider(key);
- break;
- }
+ initGeolocationModule();
}
if (config.getBoolean("web.enable")) {
@@ -380,39 +368,17 @@ public final class Context {
tripsConfig = initTripsConfig();
if (config.getBoolean("event.enable")) {
- geofenceManager = new GeofenceManager(dataManager);
- calendarManager = new CalendarManager(dataManager);
- notificationManager = new NotificationManager(dataManager);
- Properties velocityProperties = new Properties();
- velocityProperties.setProperty("file.resource.loader.path",
- Context.getConfig().getString("templates.rootPath", "templates") + "/");
- velocityProperties.setProperty("runtime.log.logsystem.class",
- "org.apache.velocity.runtime.log.NullLogChute");
-
- String address;
- try {
- address = config.getString("web.address", InetAddress.getLocalHost().getHostAddress());
- } catch (UnknownHostException e) {
- address = "localhost";
- }
-
- String webUrl = URIUtil.newURI("http", address, config.getInteger("web.port", 8082), "", "");
- webUrl = Context.getConfig().getString("web.url", webUrl);
- velocityProperties.setProperty("web.url", webUrl);
-
- velocityEngine = new VelocityEngine();
- velocityEngine.init(velocityProperties);
-
- motionEventHandler = new MotionEventHandler(tripsConfig);
- overspeedEventHandler = new OverspeedEventHandler(
- Context.getConfig().getLong("event.overspeed.minimalDuration") * 1000,
- Context.getConfig().getBoolean("event.overspeed.notRepeat"));
+ initEventsModule();
}
serverManager = new ServerManager();
if (config.getBoolean("event.forward.enable")) {
- eventForwarder = new EventForwarder();
+ if (Context.getConfig().getBoolean("event.forward.payloadAsParamMode")) {
+ eventForwarder = new MultiPartEventForwarder();
+ } else {
+ eventForwarder = new JsonTypeEventForwarder();
+ }
}
attributesManager = new AttributesManager(dataManager);
@@ -429,6 +395,59 @@ public final class Context {
}
+ private static void initGeolocationModule() {
+
+ String type = config.getString("geolocation.type", "mozilla");
+ String url = config.getString("geolocation.url");
+ String key = config.getString("geolocation.key");
+
+ switch (type) {
+ case "google":
+ geolocationProvider = new GoogleGeolocationProvider(key);
+ break;
+ case "opencellid":
+ geolocationProvider = new OpenCellIdGeolocationProvider(key);
+ break;
+ case "unwired":
+ geolocationProvider = new UnwiredGeolocationProvider(url, key);
+ break;
+ default:
+ geolocationProvider = new MozillaGeolocationProvider(key);
+ break;
+ }
+ }
+
+ private static void initEventsModule() {
+
+ geofenceManager = new GeofenceManager(dataManager);
+ calendarManager = new CalendarManager(dataManager);
+ notificationManager = new NotificationManager(dataManager);
+ Properties velocityProperties = new Properties();
+ velocityProperties.setProperty("file.resource.loader.path",
+ Context.getConfig().getString("templates.rootPath", "templates") + "/");
+ velocityProperties.setProperty("runtime.log.logsystem.class",
+ "org.apache.velocity.runtime.log.NullLogChute");
+
+ String address;
+ try {
+ address = config.getString("web.address", InetAddress.getLocalHost().getHostAddress());
+ } catch (UnknownHostException e) {
+ address = "localhost";
+ }
+
+ String webUrl = URIUtil.newURI("http", address, config.getInteger("web.port", 8082), "", "");
+ webUrl = Context.getConfig().getString("web.url", webUrl);
+ velocityProperties.setProperty("web.url", webUrl);
+
+ velocityEngine = new VelocityEngine();
+ velocityEngine.init(velocityProperties);
+
+ motionEventHandler = new MotionEventHandler(tripsConfig);
+ overspeedEventHandler = new OverspeedEventHandler(
+ Context.getConfig().getLong("event.overspeed.minimalDuration") * 1000,
+ Context.getConfig().getBoolean("event.overspeed.notRepeat"));
+ }
+
public static void init(IdentityManager testIdentityManager) {
config = new Config();
objectMapper = new ObjectMapper();
diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java
index abc424ff9..f813426d3 100644
--- a/src/org/traccar/database/DataManager.java
+++ b/src/org/traccar/database/DataManager.java
@@ -307,7 +307,7 @@ public class DataManager {
.executeQuerySingle(User.class);
LdapProvider ldapProvider = Context.getLdapProvider();
if (user != null) {
- if (ldapProvider != null && ldapProvider.login(user.getLogin(), password)
+ if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password)
|| !forceLdap && user.isPasswordValid(password)) {
return user;
}
diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java
index 07b60ba58..0e9097d25 100644
--- a/src/org/traccar/database/PermissionsManager.java
+++ b/src/org/traccar/database/PermissionsManager.java
@@ -255,7 +255,8 @@ public class PermissionsManager {
}
if (before.getReadonly() != after.getReadonly()
|| before.getDeviceReadonly() != after.getDeviceReadonly()
- || before.getDisabled() != after.getDisabled()) {
+ || before.getDisabled() != after.getDisabled()
+ || before.getLimitCommands() != after.getLimitCommands()) {
if (userId == after.getId()) {
checkAdmin(userId);
}
diff --git a/src/org/traccar/notification/EventForwarder.java b/src/org/traccar/notification/EventForwarder.java
index ac37f980c..68c3ea221 100644
--- a/src/org/traccar/notification/EventForwarder.java
+++ b/src/org/traccar/notification/EventForwarder.java
@@ -17,6 +17,9 @@ package org.traccar.notification;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder;
+import java.util.Arrays;
+import java.util.List;
+
import org.traccar.Context;
import org.traccar.helper.Log;
import org.traccar.model.Device;
@@ -27,15 +30,16 @@ import org.traccar.model.Position;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
+import com.ning.http.client.FluentCaseInsensitiveStringsMap;
-public final class EventForwarder {
+public abstract class EventForwarder {
- private String url;
- private String header;
+ private final String url;
+ private final String header;
public EventForwarder() {
url = Context.getConfig().getString("event.forward.url", "http://localhost/");
- header = Context.getConfig().getString("event.forward.header", "");
+ header = Context.getConfig().getString("event.forward.header");
}
private static final String KEY_POSITION = "position";
@@ -43,26 +47,39 @@ public final class EventForwarder {
private static final String KEY_GEOFENCE = "geofence";
private static final String KEY_DEVICE = "device";
- public void forwardEvent(Event event, Position position) {
+ public final void forwardEvent(Event event, Position position) {
BoundRequestBuilder requestBuilder = Context.getAsyncHttpClient().preparePost(url);
+ requestBuilder.setBodyEncoding(StandardCharsets.UTF_8.name());
- requestBuilder.addHeader("Content-Type", "application/json; charset=utf-8");
- if (!header.equals("")) {
- String[] headerLines = header.split("\\r?\\n");
- for (String headerLine: headerLines) {
- String[] splitedLine = headerLine.split(":", 2);
- if (splitedLine.length == 2) {
- requestBuilder.setHeader(splitedLine[0].trim(), splitedLine[1].trim());
- }
- }
+ requestBuilder.addHeader("Content-Type", getContentType());
+
+ if (header != null && !header.isEmpty()) {
+ FluentCaseInsensitiveStringsMap params = new FluentCaseInsensitiveStringsMap();
+ params.putAll(splitIntoKeyValues(header, ":"));
+ requestBuilder.setHeaders(params);
}
- requestBuilder.setBody(preparePayload(event, position));
+ setContent(event, position, requestBuilder);
requestBuilder.execute();
}
- private byte[] preparePayload(Event event, Position position) {
+ protected Map<String, List<String>> splitIntoKeyValues(String params, String separator) {
+
+ String[] splitedLine;
+ Map<String, List<String>> paramsMap = new HashMap<>();
+ String[] paramsLines = params.split("\\r?\\n");
+
+ for (String paramLine: paramsLines) {
+ splitedLine = paramLine.split(separator, 2);
+ if (splitedLine.length == 2) {
+ paramsMap.put(splitedLine[0].trim(), Arrays.asList(splitedLine[1].trim()));
+ }
+ }
+ return paramsMap;
+ }
+
+ protected String prepareJsonPayload(Event event, Position position) {
Map<String, Object> data = new HashMap<>();
data.put(KEY_EVENT, event);
if (position != null) {
@@ -81,11 +98,14 @@ public final class EventForwarder {
}
}
try {
- return Context.getObjectMapper().writeValueAsString(data).getBytes(StandardCharsets.UTF_8);
+ return Context.getObjectMapper().writeValueAsString(data);
} catch (JsonProcessingException e) {
Log.warning(e);
return null;
}
}
+ protected abstract String getContentType();
+ protected abstract void setContent(Event event, Position position, BoundRequestBuilder requestBuilder);
+
}
diff --git a/src/org/traccar/notification/JsonTypeEventForwarder.java b/src/org/traccar/notification/JsonTypeEventForwarder.java
new file mode 100644
index 000000000..c1e4220d0
--- /dev/null
+++ b/src/org/traccar/notification/JsonTypeEventForwarder.java
@@ -0,0 +1,20 @@
+package org.traccar.notification;
+
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder;
+
+public class JsonTypeEventForwarder extends EventForwarder {
+
+ @Override
+ protected String getContentType() {
+ return "application/json; charset=utf-8";
+ }
+
+ @Override
+ protected void setContent(Event event, Position position, BoundRequestBuilder requestBuilder) {
+ requestBuilder.setBody(prepareJsonPayload(event, position));
+ }
+
+}
diff --git a/src/org/traccar/notification/MultiPartEventForwarder.java b/src/org/traccar/notification/MultiPartEventForwarder.java
new file mode 100644
index 000000000..f4c36d3e4
--- /dev/null
+++ b/src/org/traccar/notification/MultiPartEventForwarder.java
@@ -0,0 +1,46 @@
+package org.traccar.notification;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.traccar.Context;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder;
+import com.ning.http.client.multipart.StringPart;
+
+public class MultiPartEventForwarder extends EventForwarder {
+
+ private final String payloadParamName;
+ private final String additionalParams;
+
+ public MultiPartEventForwarder() {
+ payloadParamName = Context.getConfig().getString("event.forward.paramMode.payloadParamName", "payload");
+ additionalParams = Context.getConfig().getString("event.forward.paramMode.additionalParams");
+ }
+
+ @Override
+ protected String getContentType() {
+ return "multipart/form-data";
+ }
+
+ @Override
+ protected void setContent(Event event, Position position, BoundRequestBuilder requestBuilder) {
+
+ if (additionalParams != null && !additionalParams.isEmpty()) {
+ Map<String, List<String>> paramsToAdd = splitIntoKeyValues(additionalParams, "=");
+
+ for (Entry<String, List<String>> param : paramsToAdd.entrySet()) {
+ for (String singleParamValue : param.getValue()) {
+ requestBuilder.addBodyPart(new StringPart(param.getKey(), singleParamValue, null,
+ StandardCharsets.UTF_8));
+ }
+ }
+ }
+ requestBuilder.addBodyPart(new StringPart(payloadParamName,
+ prepareJsonPayload(event, position), "application/json", StandardCharsets.UTF_8));
+ }
+}
diff --git a/src/org/traccar/notification/NotificationFormatter.java b/src/org/traccar/notification/NotificationFormatter.java
index 8da819430..114825a83 100644
--- a/src/org/traccar/notification/NotificationFormatter.java
+++ b/src/org/traccar/notification/NotificationFormatter.java
@@ -18,6 +18,7 @@ package org.traccar.notification;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
import java.util.Locale;
import org.apache.velocity.Template;
@@ -39,6 +40,7 @@ public final class NotificationFormatter {
}
public static VelocityContext prepareContext(long userId, Event event, Position position) {
+
User user = Context.getPermissionsManager().getUser(userId);
Device device = Context.getIdentityManager().getById(event.getDeviceId());
@@ -68,31 +70,46 @@ public final class NotificationFormatter {
}
public static Template getTemplate(Event event, String path) {
+
+ String templateFilePath;
Template template;
+
try {
- template = Context.getVelocityEngine().getTemplate(path + event.getType() + ".vm",
- StandardCharsets.UTF_8.name());
+ templateFilePath = Paths.get(path, event.getType() + ".vm").toString();
+ template = Context.getVelocityEngine().getTemplate(templateFilePath, StandardCharsets.UTF_8.name());
} catch (ResourceNotFoundException error) {
Log.warning(error);
- template = Context.getVelocityEngine().getTemplate(path + "unknown.vm",
- StandardCharsets.UTF_8.name());
+ templateFilePath = Paths.get(path, "unknown.vm").toString();
+ template = Context.getVelocityEngine().getTemplate(templateFilePath, StandardCharsets.UTF_8.name());
}
return template;
}
public static MailMessage formatMailMessage(long userId, Event event, Position position) {
+ String templatePath = Context.getConfig().getString("mail.templatesPath", "mail");
VelocityContext velocityContext = prepareContext(userId, event, position);
- StringWriter writer = new StringWriter();
- getTemplate(event, Context.getConfig().getString("mail.templatesPath", "mail") + "/")
- .merge(velocityContext, writer);
- return new MailMessage((String) velocityContext.get("subject"), writer.toString());
+ String formattedMessage = formatMessage(velocityContext, userId, event, position, templatePath);
+
+ return new MailMessage((String) velocityContext.get("subject"), formattedMessage);
}
public static String formatSmsMessage(long userId, Event event, Position position) {
- VelocityContext velocityContext = prepareContext(userId, event, position);
+ String templatePath = Context.getConfig().getString("sms.templatesPath", "sms");
+
+ return formatMessage(null, userId, event, position, templatePath);
+ }
+
+ private static String formatMessage(VelocityContext vc, Long userId, Event event, Position position,
+ String templatePath) {
+
+ VelocityContext velocityContext = vc;
+ if (velocityContext == null) {
+ velocityContext = prepareContext(userId, event, position);
+ }
StringWriter writer = new StringWriter();
- getTemplate(event, Context.getConfig().getString("sms.templatesPath", "sms") + "/")
- .merge(velocityContext, writer);
+ getTemplate(event, templatePath).merge(velocityContext, writer);
+
return writer.toString();
}
+
}
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;
}
diff --git a/test/org/traccar/protocol/EelinkProtocolDecoderTest.java b/test/org/traccar/protocol/EelinkProtocolDecoderTest.java
index 115eef1a3..aaf58b438 100644
--- a/test/org/traccar/protocol/EelinkProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/EelinkProtocolDecoderTest.java
@@ -11,6 +11,18 @@ public class EelinkProtocolDecoderTest extends ProtocolTest {
EelinkProtocolDecoder decoder = new EelinkProtocolDecoder(new EelinkProtocol());
verifyNull(decoder, binary(
+ "454C0027E753035254407167747167670100180002035254407167747100200205020500010432000086BD"));
+
+ verifyPosition(decoder, binary(
+ "676780005a000001000000004c61743a4e33312e38333935352c4c6f6e3a5738322e36313334362c436f757273653a302e30302c53706565643a302e30306b6d2f682c4461746554696d653a323031372d31322d30322031313a32393a3433"));
+
+ verifyPosition(decoder, binary(
+ "676780005E5788014C754C754C61743A4E32332E3131313734330A4C6F6E3A453131342E3430393233380A436F757273653A302E30300A53706565643A302E31374B4D2F480A446174652054696D653A323031352D30392D31332032303A32313A3230"));
+
+ verifyPosition(decoder, binary(
+ "454C0050EAE2035254407167747167671200410021590BD93803026B940D0C3952AD0021000000000501CC0001A53F0170F0AB1305890F11000000000000C2D0001C001600000000000000000000000000000000"));
+
+ verifyNull(decoder, binary(
"676701000c007b03525440717505180104"));
verifyPosition(decoder, binary(
@@ -43,7 +55,7 @@ public class EelinkProtocolDecoderTest extends ProtocolTest {
verifyPosition(decoder, binary(
"676702002509f65868507603a1e92e03cf90fe000000019f000117ee00111e0120631145003101510000"));
- verifyPosition(decoder, binary(
+ verifyAttributes(decoder, binary(
"676712001e0092579714d60201f90001785003a301cd1a006a118504f2000000000000"));
verifyPosition(decoder, binary(
diff --git a/test/org/traccar/protocol/EelinkProtocolEncoderTest.java b/test/org/traccar/protocol/EelinkProtocolEncoderTest.java
index 8a8cd5f6b..e4502f919 100644
--- a/test/org/traccar/protocol/EelinkProtocolEncoderTest.java
+++ b/test/org/traccar/protocol/EelinkProtocolEncoderTest.java
@@ -9,13 +9,13 @@ public class EelinkProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- EelinkProtocolEncoder encoder = new EelinkProtocolEncoder();
-
Command command = new Command();
command.setDeviceId(1);
command.setType(Command.TYPE_ENGINE_STOP);
- verifyCommand(encoder, command, binary("676780000f0000010000000052454c41592c3123"));
+ verifyCommand(new EelinkProtocolEncoder(false), command, binary("676780000f0000010000000052454c41592c3123"));
+
+ verifyCommand(new EelinkProtocolEncoder(true), command, binary("454c001eb41a0123456789012345676780000f0000010000000052454c41592c3123"));
}
diff --git a/test/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/test/org/traccar/protocol/Gt06ProtocolDecoderTest.java
index c9ef29791..b6493e85b 100644
--- a/test/org/traccar/protocol/Gt06ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/Gt06ProtocolDecoderTest.java
@@ -17,6 +17,30 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
"78780D01086471700328358100093F040D0A"));
verifyAttributes(decoder, binary(
+ "78780B23C00122040001000818720D0A"));
+
+ verifyNotNull(decoder, binary(
+ "787880a2110b161010140136040000591200000000009d7c01020000591200000000009d7c01020000591200000000009d7c01020000591200000000009d7c01020000591200000000009d7c01020000591200000000009d7c01020000591200000000009d7c0102ff033c1e04ddc28aa6001801eb4039c90000000000000014db84730d0a"));
+
+ verifyNotNull(decoder, binary(
+ "78782ba701cc000000919100000000090617032b3836313832323038343735363200000000000000000100049fb60d0a"));
+
+ verifyNotNull(decoder, binary(
+ "787819a501cc0000009191000000000906170304050400010005f44d0d0a"));
+
+ verifyNotNull(decoder, binary(
+ "78782ca3110b10081336f000000000000000000004003901cc0000009191000000000906170304050400010003e0940d0a"));
+
+ verifyNotNull(decoder, binary(
+ "7878A3A2110B0603201501CC010000254E000000000615F804000000254E000000000615F804000000254E000000000615F804000000254E000000000615F804000000254E000000000615F804000000254E000000000615F804000000254E000000000615F80400FF08F483CD4DF4C0D750BD5F8BC5CECFB0D59DAFB459CDA8574E8424C6CC50BD5F6C7E1CC9B0D59D8AA718C90087363040E0C83496727B4DE4C7002919670D0A"));
+
+ verifyNotNull(decoder, binary(
+ "78786CA1110B0413093801CC01000025FC000000000618C10201000025FC000000000618C10201000025FC000000000618C10201000025FC000000000618C10201000025FC000000000618C10201000025FC000000000618C10201000025FC000000000618C10201FF0002000541D70D0A"));
+
+ verifyPosition(decoder, binary(
+ "787822220F0C1D023305C9027AC8180C46586000140001CC00287D001F71000001000820860D0A"));
+
+ verifyAttributes(decoder, binary(
"797900262100000000020043006f006d006d0061006e00640020006500720072006f0072002100236e850d0a"));
verifyNotNull(decoder, binary(
@@ -206,6 +230,12 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
verifyNull(decoder, binary(
"787801080d0a"));
+ verifyNull(decoder, binary(
+ "78782E2A0F0C1D071139CA027AC8000C4658000014D83132353230313335333231373730373900000000000001002A6ECE0D0A"));
+
+ verifyNull(decoder, binary(
+ "7878058A000688290D0A"));
+
}
}
diff --git a/test/org/traccar/protocol/Jt600FrameDecoderTest.java b/test/org/traccar/protocol/Jt600FrameDecoderTest.java
index afa53ba13..15e6ec18c 100644
--- a/test/org/traccar/protocol/Jt600FrameDecoderTest.java
+++ b/test/org/traccar/protocol/Jt600FrameDecoderTest.java
@@ -11,23 +11,27 @@ public class Jt600FrameDecoderTest extends ProtocolTest {
Jt600FrameDecoder decoder = new Jt600FrameDecoder();
- Assert.assertEquals(
+ verifyFrame(
+ binary("24315011626912001b21111718095900000000000000000e0000005c000000000000000000"),
+ decoder.decode(null, null, binary("24315011626912001b21111718095900000000000000000e0000005c00000000000000000024315011626912001b22111708130400000000000000000e0000005a00000000000000000024315011626912001b22111708140400000000000000000e0000005a000000723e18a61b01")));
+
+ verifyFrame(
binary("2475604055531611002311111600311326144436028210791d016c0000001f070000000020c03c4f6d07d80ccf"),
decoder.decode(null, null, binary("2475604055531611002311111600311326144436028210791d016c0000001f070000000020c03c4f6d07d80ccf")));
- Assert.assertEquals(
+ verifyFrame(
binary("2475605035891613002328091601152806086750106533350c00000000000a000000000000e1ff4f97007f1607"),
decoder.decode(null, null, binary("2475605035891613002328091601152806086750106533350c00000000000a000000000000e1ff4f97007f1607")));
- Assert.assertEquals(
+ verifyFrame(
binary("28333132303832303032392C5730312C30323535332E333535352C452C323433382E303939372C532C412C3137313031322C3035333333392C302C382C32302C362C33312C352C32302C323029"),
decoder.decode(null, null, binary("28333132303832303032392C5730312C30323535332E333535352C452C323433382E303939372C532C412C3137313031322C3035333333392C302C382C32302C362C33312C352C32302C323029")));
- Assert.assertEquals(
+ verifyFrame(
binary("24312082002911001B171012053405243809970255335555000406140003EE2B91044D1F02"),
decoder.decode(null, null, binary("24312082002911001B171012053405243809970255335555000406140003EE2B91044D1F02")));
- Assert.assertEquals(
+ verifyFrame(
binary("28373536303430353535332c404a5429"),
decoder.decode(null, null, binary("28373536303430353535332c404a5429")));
diff --git a/test/org/traccar/protocol/Jt600ProtocolDecoderTest.java b/test/org/traccar/protocol/Jt600ProtocolDecoderTest.java
index 33959bc29..dd01ef783 100644
--- a/test/org/traccar/protocol/Jt600ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/Jt600ProtocolDecoderTest.java
@@ -12,6 +12,9 @@ public class Jt600ProtocolDecoderTest extends ProtocolTest {
Jt600ProtocolDecoder decoder = new Jt600ProtocolDecoder(new Jt600Protocol());
verifyPositions(decoder, binary(
+ "2475609213701711002701010000020200000000000000000e00000000000f000000000020c164cd7b00d516000f0f0f02"));
+
+ verifyPositions(decoder, binary(
"24657060730131001b13111710361906538525079524797f000000000000000003f300036c"));
verifyPositions(decoder, binary(
diff --git a/test/org/traccar/protocol/Pt502ProtocolDecoderTest.java b/test/org/traccar/protocol/Pt502ProtocolDecoderTest.java
index fe66876ed..8fd1b4ff7 100644
--- a/test/org/traccar/protocol/Pt502ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/Pt502ProtocolDecoderTest.java
@@ -2,6 +2,7 @@ package org.traccar.protocol;
import org.junit.Test;
import org.traccar.ProtocolTest;
+import org.traccar.model.Position;
public class Pt502ProtocolDecoderTest extends ProtocolTest {
@@ -39,7 +40,10 @@ public class Pt502ProtocolDecoderTest extends ProtocolTest {
verifyPosition(decoder, text(
"$FDA,40456789,083125.000,A,2232.0971,N,11400.9504,E,0.0,5.00,090714,,,A/00000,00/0,0/200076//FE7/"));
-
+
+ verifyAttribute(decoder, text(
+ "$CPA,40456789,083125.000,A,2232.0971,N,11400.9504,E,7.62,265.24,291117,,,A/00000,00000/0/1200//#"), Position.KEY_ALARM, Position.ALARM_POWER_CUT);
+
verifyPosition(decoder, text(
"$POS,216769295715,163237.000,A,3258.1738,S,02755.4350,E,0.00,215.88,100915,,,A/0000,0//232300//5b3/"),
position("2015-09-10 16:32:37.000", true, -32.96956, 27.92392));
@@ -61,13 +65,13 @@ public class Pt502ProtocolDecoderTest extends ProtocolTest {
verifyPosition(decoder, text(
"$PHO0,6091,233606.000,A,0902.9855,N,06944.3654,W,0.0,43.8,141112,,,A/00010,00000/0/224000//"));
-
+
verifyPosition(decoder, text(
"$POS,353451000164,082405.000,A,1254.8501,N,10051.6752,E,0.00,237.99,160513,,,A/0000,0/0/55000//a71/"));
-
+
verifyPosition(decoder, text(
"$POS,012896008586486,154215.000,A,0118.0143,S,03646.9144,E,0.00,83.29,180714,,,A/0000,0/0/29200//644/"));
-
+
verifyPosition(decoder, text(
"$POS,1151000,205326.000,A,0901.3037,N,07928.2751,W,48.79,30.55,170814,,,A/00010,10000/0,0,0,0/15986500//fb8/"));
diff --git a/test/org/traccar/protocol/SigfoxProtocolDecoderTest.java b/test/org/traccar/protocol/SigfoxProtocolDecoderTest.java
new file mode 100644
index 000000000..86ae225ee
--- /dev/null
+++ b/test/org/traccar/protocol/SigfoxProtocolDecoderTest.java
@@ -0,0 +1,19 @@
+package org.traccar.protocol;
+
+import org.jboss.netty.handler.codec.http.HttpMethod;
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class SigfoxProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ SigfoxProtocolDecoder decoder = new SigfoxProtocolDecoder(new SigfoxProtocol());
+
+ verifyPosition(decoder, request(HttpMethod.POST, "/",
+ buffer("%7B++%22device%22%3A%222BF839%22%2C++%22time%22%3A1510605882%2C++%22duplicate%22%3Afalse%2C++%22snr%22%3A45.61%2C++%22station%22%3A%2235A9%22%2C++%22data%22%3A%2200bd6475e907398e562d01b9%22%2C++%22avgSnr%22%3A45.16%2C++%22lat%22%3A-38.0%2C++%22lng%22%3A145.0%2C++%22rssi%22%3A-98.00%2C++%22seqNumber%22%3A228+%7D=")));
+
+ }
+
+}
diff --git a/test/org/traccar/protocol/TmgFrameDecoderTest.java b/test/org/traccar/protocol/TmgFrameDecoderTest.java
new file mode 100644
index 000000000..7a6c47fb9
--- /dev/null
+++ b/test/org/traccar/protocol/TmgFrameDecoderTest.java
@@ -0,0 +1,24 @@
+package org.traccar.protocol;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class TmgFrameDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ TmgFrameDecoder decoder = new TmgFrameDecoder();
+
+ verifyFrame(
+ binary("24696f662c3836343530323033373939393630342c323238323133323031372c383132343238302c302c3239393133363231362e2d3438323235383537362ca52c313337393234353339382e3831383733343637362c142c2d36393936393937332e302c313135333435343433372e2d313938363833343039322c3439323039373739392c32302c302c2d3332302c302c4c4c4c4c2c4e4e544e2c48482c302e31372c332e30312c3330313131363030312c302c56455230302e3161"),
+ decoder.decode(null, null, binary("111538360b383634353032303337393939363034eb0b1c8d00ffff23000000000000000000000000000000001c9401008c320c00188901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000001d940100c8950100bd0024696f662c3836343530323033373939393630342c323238323133323031372c383132343238302c302c3239393133363231362e2d3438323235383537362ca52c313337393234353339382e3831383733343637362c142c2d36393936393937332e302c313135333435343433372e2d313938363833343039322c3439323039373739392c32302c302c2d3332302c302c4c4c4c4c2c4e4e544e2c48482c302e31372c332e30312c3330313131363030312c302c56455230302e31610a000195010090960100bd0024746d702c3836343530323033373939393630342c323238323133323031372c383132343238302c302c3239393133363231362e2d3438323235383537362ca52c313337393234353339382e3831383733343637362c142c2d36393936393937332e302c313135333435343433372e2d313938363833343039322c3439323039373739392c32302c302c2d3237372c302c4c4c4c4c2c4e4e544e2c48482c302e31372c332e30312c3330313131363030312c302c56455230302e31610a00c9950100289701008b002462616b2c3836343530323033373939393630342c32313131323031372c3132303230312c312c323832362e353938312c4e2c30373731382e363436352c452c3030302e302c3239382e35322c35323834372c32322c332c2d3233392c302c4c4c4c4c2c4e4e544e2c48482c302e32342c332e30332c3330313131363030312c302c56455230302e31610a00000091960100c09701008b002462616b2c3836343530323033373939393630342c32313131323031372c3132303231322c312c323832362e353938312c4e2c30373731382e363437322c452c3030302e302c3037392e34322c35323834372c32332c332c2d3230352c302c4c4c4c4c2c4e4e544e2c48482c302e31352c332e30332c3330313131363030312c302c56455230302e31610a00000029970100589801008a002462616b2c3836343530323033373939393630342c32313131323031372c3132303232322c312c323832362e353938302c4e2c30373731382e363438352c452c3030302e302c3037372e332c35323834372c32332c332c2d3137342c302c4c4c4c4c2c4e4e544e2c48482c302e31382c332e30332c3330313131363030312c302c56455230302e31610a00000000c1970100f09801008a002462616b2c3836343530323033373939393630342c32313131323031372c3132303233312c312c323832362e353936342c4e2c30373731382e363437312c452c3030302e302c3133312e352c35323834372c32322c342c2d3134362c302c4c4c4c4c2c4e4e544e2c48482c302e31392c332e30332c3330313131363030312c302c56455230302e31610a0000000059980100889901008b002462616b2c3836343530323033373939393630342c32313131323031372c3132303234332c312c323832362e353935382c4e2c30373731382e363436382c452c3030302e302c3133392e36362c35323834372c32322c342c2d3132312c302c4c4c4c4c2c4e4e544e2c48482c302e31322c332e30332c3330313131363030312c302c56455230302e31610a000000f1980100209a01008a002462616b2c3836343530323033373939393630342c32313131323031372c3132303235332c312c323832362e353934392c4e2c30373731382e363436")));
+
+ verifyFrame(
+ binary("246c6f632c3836343530323033303335323734342c32393131323031372c3038333034392c312c323533342e363733312c4e2c30383733342e363735352c452c3033382e302c3037372e31392c35343234312c362c31312c3130302c302c48484c4c2c4e4e4e4e2c48482c302e31342c332e31312c3330313131363030312c332c56455230302e3161"),
+ decoder.decode(null, null, binary("246c6f632c3836343530323033303335323734342c32393131323031372c3038333034392c312c323533342e363733312c4e2c30383733342e363735352c452c3033382e302c3037372e31392c35343234312c362c31312c3130302c302c48484c4c2c4e4e4e4e2c48482c302e31342c332e31312c3330313131363030312c332c56455230302e31610a246c6f632c3836343530323033303335323734342c32393131323031372c3038333035392c312c323533342e363634322c4e2c30383733342e373333352c452c3032392e302c3132322e37302c35343234312c362c31312c3130302c302c48484c4c2c4e4e4e4e2c48482c302e31342c332e31312c3330313131363030312c342c56455230302e31610a246c6f632c3836343530323033303335323734342c32393131323031372c3038333130392c312c323533342e363531362c4e2c30383733342e373938312c452c3034342e302c3039342e39382c36303631322c31312c31312c3130302c302c48484c4c2c4e4e4e4e2c48482c302e31372c332e31302c3330313131363030312c342c56455230302e31610a246c6f632c3836343530323033303335323734342c32393131323031372c3038333131392c312c323533342e363432312c4e2c30383733342e383639312c452c3033352e302c3130312e37332c36303631322c31322c31312c3130302c302c48484c4c2c4e4e4e4e2c48482c302e31342c332e31312c3330313131363030312c342c56455230302e31610a246c6f632c3836343530323033303335323734342c32393131323031372c3038333132392c312c323533342e363335352c4e2c30383733342e393135322c452c3032302e302c3131312e31322c36303631322c31322c31312c3130302c302c48484c4c2c4e4e4e4e2c48482c302e31362c332e31312c3330313131363030312c342c56455230302e31610a")));
+
+ }
+
+}
diff --git a/test/org/traccar/protocol/TmgProtocolDecoderTest.java b/test/org/traccar/protocol/TmgProtocolDecoderTest.java
index 2fac25dab..fd027eddf 100644
--- a/test/org/traccar/protocol/TmgProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/TmgProtocolDecoderTest.java
@@ -11,6 +11,15 @@ public class TmgProtocolDecoderTest extends ProtocolTest {
TmgProtocolDecoder decoder = new TmgProtocolDecoder(new TmgProtocol());
verifyPosition(decoder, text(
+ "$loc,869309013800417,08032014,094459,1,2826.1956,N,07659.7690,E,0.0,2.5,4441,31,6,95,1,LLLL,NNTN,HH,0.15,0.26,HR38AU1389,0,SW0.1a"));
+
+ verifyPosition(decoder, text(
+ "$bak,864502037999604,21112017,120243,1,2826.5958,N,07718.6468,E,000.0,139.66,52847,22,4,-174,0,LLLL,NNTN,HH,0.12,3.03,301116001,0,VER00.1a"));
+
+ verifyNull(decoder, text(
+ "$iof,864502037999604,2282132017,8124280,0,299136216.-482258576,¥,1379245398.818734676,,-69969973.0,1153454437.-1986834092,492097799,20,0,-320,0,LLLL,NNTN,HH,0.17,3.01,301116001,0,VER00.1a"));
+
+ verifyPosition(decoder, text(
"$nor,L,868325023006341,14022017,103947,1,2836.6542,N,07706.2504,E,0.0,0.0,0.0,0.0,0,22,VODAFONE - DELH,15,49B7,1,2.57,13.2,00000010,00000000,0111,00.0,00.0,0.0,SW10.12,NA,#"));
verifyPosition(decoder, text(