aboutsummaryrefslogtreecommitdiff
path: root/src/org/traccar
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/traccar')
-rw-r--r--src/org/traccar/DistanceHandler.java11
-rw-r--r--src/org/traccar/MainEventHandler.java5
-rw-r--r--src/org/traccar/api/AsyncSocket.java6
-rw-r--r--src/org/traccar/api/AsyncSocketServlet.java11
-rw-r--r--src/org/traccar/api/CorsResponseFilter.java14
-rw-r--r--src/org/traccar/api/SecurityRequestFilter.java5
-rw-r--r--src/org/traccar/api/resource/DevicePermissionResource.java (renamed from src/org/traccar/api/resource/PermissionResource.java)12
-rw-r--r--src/org/traccar/api/resource/GroupPermissionResource.java52
-rw-r--r--src/org/traccar/api/resource/GroupResource.java85
-rw-r--r--src/org/traccar/api/resource/PositionResource.java11
-rw-r--r--src/org/traccar/database/DataManager.java101
-rw-r--r--src/org/traccar/database/GroupTree.java153
-rw-r--r--src/org/traccar/database/PermissionsManager.java56
-rw-r--r--src/org/traccar/helper/Checksum.java13
-rw-r--r--src/org/traccar/helper/ObdDecoder.java39
-rw-r--r--src/org/traccar/helper/Parser.java7
-rw-r--r--src/org/traccar/model/Device.java12
-rw-r--r--src/org/traccar/model/DevicePermission.java (renamed from src/org/traccar/model/Permission.java)4
-rw-r--r--src/org/traccar/model/Event.java1
-rw-r--r--src/org/traccar/model/Group.java50
-rw-r--r--src/org/traccar/model/GroupPermission.java40
-rw-r--r--src/org/traccar/protocol/AplicomProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/AstraProtocol.java43
-rw-r--r--src/org/traccar/protocol/AstraProtocolDecoder.java119
-rw-r--r--src/org/traccar/protocol/BoxProtocol.java2
-rw-r--r--src/org/traccar/protocol/CarscopProtocol.java2
-rw-r--r--src/org/traccar/protocol/CastelProtocolDecoder.java40
-rw-r--r--src/org/traccar/protocol/CityeasyProtocol.java2
-rw-r--r--src/org/traccar/protocol/FlextrackProtocol.java2
-rw-r--r--src/org/traccar/protocol/Gl100Protocol.java4
-rw-r--r--src/org/traccar/protocol/Gl200Protocol.java8
-rw-r--r--src/org/traccar/protocol/Gl200ProtocolDecoder.java414
-rw-r--r--src/org/traccar/protocol/GlobalSatProtocol.java2
-rw-r--r--src/org/traccar/protocol/GoSafeProtocol.java2
-rw-r--r--src/org/traccar/protocol/Gps103Protocol.java8
-rw-r--r--src/org/traccar/protocol/Gps103ProtocolDecoder.java9
-rw-r--r--src/org/traccar/protocol/GpsGateProtocol.java2
-rw-r--r--src/org/traccar/protocol/GpsGateProtocolDecoder.java60
-rw-r--r--src/org/traccar/protocol/GpsmtaProtocol.java2
-rw-r--r--src/org/traccar/protocol/Gt06FrameDecoder.java12
-rw-r--r--src/org/traccar/protocol/Gt06Protocol.java2
-rw-r--r--src/org/traccar/protocol/HomtecsProtocol.java43
-rw-r--r--src/org/traccar/protocol/HomtecsProtocolDecoder.java83
-rw-r--r--src/org/traccar/protocol/IntellitracProtocol.java2
-rwxr-xr-xsrc/org/traccar/protocol/KenjiProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/KhdProtocol.java2
-rw-r--r--src/org/traccar/protocol/LaipacProtocol.java2
-rw-r--r--src/org/traccar/protocol/ManPowerProtocol.java2
-rw-r--r--src/org/traccar/protocol/MegastekProtocol.java2
-rw-r--r--src/org/traccar/protocol/MeiligaoProtocol.java4
-rw-r--r--src/org/traccar/protocol/MeiligaoProtocolDecoder.java19
-rw-r--r--src/org/traccar/protocol/MeitrackProtocol.java8
-rw-r--r--src/org/traccar/protocol/MeitrackProtocolDecoder.java16
-rw-r--r--src/org/traccar/protocol/MeitrackProtocolEncoder.java23
-rw-r--r--src/org/traccar/protocol/Mta6Protocol.java2
-rw-r--r--src/org/traccar/protocol/MtxProtocol.java2
-rw-r--r--src/org/traccar/protocol/MxtProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/OsmAndProtocol.java2
-rw-r--r--src/org/traccar/protocol/PathAwayProtocol.java2
-rw-r--r--src/org/traccar/protocol/PiligrimProtocol.java2
-rw-r--r--src/org/traccar/protocol/Pt3000Protocol.java2
-rw-r--r--src/org/traccar/protocol/SuntechProtocol.java4
-rw-r--r--src/org/traccar/protocol/T55Protocol.java2
-rw-r--r--src/org/traccar/protocol/T55ProtocolDecoder.java22
-rw-r--r--src/org/traccar/protocol/TaipProtocol.java3
-rw-r--r--src/org/traccar/protocol/TelicFrameDecoder.java54
-rw-r--r--src/org/traccar/protocol/TelicProtocol.java47
-rw-r--r--src/org/traccar/protocol/TelicProtocolDecoder.java (renamed from src/org/traccar/protocol/TelikProtocolDecoder.java)26
-rw-r--r--src/org/traccar/protocol/TeltonikaProtocol.java9
-rw-r--r--src/org/traccar/protocol/Tk102Protocol.java2
-rw-r--r--src/org/traccar/protocol/Tk103Protocol.java4
-rw-r--r--src/org/traccar/protocol/Tlt2hProtocol.java2
-rw-r--r--src/org/traccar/protocol/TotemProtocol.java4
-rw-r--r--src/org/traccar/protocol/Tr20Protocol.java2
-rw-r--r--src/org/traccar/protocol/Tr900Protocol.java4
-rw-r--r--src/org/traccar/protocol/TrackboxProtocol.java2
-rw-r--r--src/org/traccar/protocol/TrvProtocol.java2
-rw-r--r--src/org/traccar/protocol/TrvProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/Tt8850Protocol.java (renamed from src/org/traccar/protocol/TelikProtocol.java)12
-rw-r--r--src/org/traccar/protocol/Tt8850ProtocolDecoder.java101
-rw-r--r--src/org/traccar/protocol/UlbotechProtocolDecoder.java4
-rw-r--r--src/org/traccar/protocol/WatchProtocol.java2
-rw-r--r--src/org/traccar/protocol/WialonProtocol.java2
-rw-r--r--src/org/traccar/protocol/XexunProtocolDecoder.java6
-rw-r--r--src/org/traccar/protocol/XirgoProtocol.java2
-rw-r--r--src/org/traccar/protocol/YwtProtocol.java2
-rw-r--r--src/org/traccar/web/AsyncServlet.java2
-rw-r--r--src/org/traccar/web/BaseServlet.java2
-rw-r--r--src/org/traccar/web/WebServer.java7
89 files changed, 1692 insertions, 288 deletions
diff --git a/src/org/traccar/DistanceHandler.java b/src/org/traccar/DistanceHandler.java
index 1586d116b..c737457f6 100644
--- a/src/org/traccar/DistanceHandler.java
+++ b/src/org/traccar/DistanceHandler.java
@@ -1,5 +1,6 @@
/*
* Copyright 2015 Amila Silva
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,11 +41,13 @@ public class DistanceHandler extends BaseDataHandler {
distance = ((Number) last.getAttributes().get(Event.KEY_DISTANCE)).doubleValue();
}
- distance += DistanceCalculator.distance(
- position.getLatitude(), position.getLongitude(),
- last.getLatitude(), last.getLongitude());
+ if (position.getValid()) {
+ distance += DistanceCalculator.distance(
+ position.getLatitude(), position.getLongitude(),
+ last.getLatitude(), last.getLongitude());
- distance = BigDecimal.valueOf(distance).setScale(2, RoundingMode.HALF_EVEN).doubleValue();
+ distance = BigDecimal.valueOf(distance).setScale(2, RoundingMode.HALF_EVEN).doubleValue();
+ }
}
position.set(Event.KEY_DISTANCE, distance);
diff --git a/src/org/traccar/MainEventHandler.java b/src/org/traccar/MainEventHandler.java
index f0ef36e5b..f99765de4 100644
--- a/src/org/traccar/MainEventHandler.java
+++ b/src/org/traccar/MainEventHandler.java
@@ -48,7 +48,10 @@ public class MainEventHandler extends IdleStateAwareChannelHandler {
s.append("course: ").append(String.format("%.1f", position.getCourse()));
Log.info(s.toString());
- Context.getConnectionManager().updatePosition(position);
+ Position lastPosition = Context.getConnectionManager().getLastPosition(position.getDeviceId());
+ if (lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) > 0) {
+ Context.getConnectionManager().updatePosition(position);
+ }
}
}
diff --git a/src/org/traccar/api/AsyncSocket.java b/src/org/traccar/api/AsyncSocket.java
index 7de182d7e..c289367ea 100644
--- a/src/org/traccar/api/AsyncSocket.java
+++ b/src/org/traccar/api/AsyncSocket.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U
private Collection<Long> devices;
public AsyncSocket(long userId) {
- devices = Context.getPermissionsManager().allowedDevices(userId);
+ devices = Context.getPermissionsManager().getDevicePermissions(userId);
}
@Override
@@ -66,7 +66,7 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U
}
private void sendData(String key, Collection<?> data) {
- if (!data.isEmpty()) {
+ if (!data.isEmpty() && isConnected()) {
JsonObjectBuilder json = Json.createObjectBuilder();
json.add(key, JsonConverter.arrayToJson(data));
getRemote().sendString(json.build().toString(), null);
diff --git a/src/org/traccar/api/AsyncSocketServlet.java b/src/org/traccar/api/AsyncSocketServlet.java
index fbfe248e5..ef6cef732 100644
--- a/src/org/traccar/api/AsyncSocketServlet.java
+++ b/src/org/traccar/api/AsyncSocketServlet.java
@@ -20,6 +20,7 @@ import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
+import org.traccar.Context;
import org.traccar.api.resource.SessionResource;
public class AsyncSocketServlet extends WebSocketServlet {
@@ -28,12 +29,16 @@ public class AsyncSocketServlet extends WebSocketServlet {
@Override
public void configure(WebSocketServletFactory factory) {
- factory.getPolicy().setIdleTimeout(ASYNC_TIMEOUT);
+ factory.getPolicy().setIdleTimeout(Context.getConfig().getLong("web.timeout", ASYNC_TIMEOUT));
factory.setCreator(new WebSocketCreator() {
@Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp) {
- long userId = (Long) req.getSession().getAttribute(SessionResource.USER_ID_KEY);
- return new AsyncSocket(userId);
+ if (req.getSession() != null) {
+ long userId = (Long) req.getSession().getAttribute(SessionResource.USER_ID_KEY);
+ return new AsyncSocket(userId);
+ } else {
+ return null;
+ }
}
});
}
diff --git a/src/org/traccar/api/CorsResponseFilter.java b/src/org/traccar/api/CorsResponseFilter.java
index 001f6ab4c..178d08812 100644
--- a/src/org/traccar/api/CorsResponseFilter.java
+++ b/src/org/traccar/api/CorsResponseFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,6 @@ import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.traccar.Context;
import java.io.IOException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
@@ -37,7 +35,7 @@ public class CorsResponseFilter implements ContainerResponseFilter {
public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE = "true";
public static final String ACCESS_CONTROL_ALLOW_METHODS_KEY = "Access-Control-Allow-Methods";
- public static final String ACCESS_CONTROL_ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE";
+ public static final String ACCESS_CONTROL_ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE, OPTIONS";
@Override
public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException {
@@ -54,11 +52,11 @@ public class CorsResponseFilter implements ContainerResponseFilter {
if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN_KEY)) {
String origin = request.getHeaderString(HttpHeaders.Names.ORIGIN);
String allowed = Context.getConfig().getString("web.origin");
- if (allowed == null) {
+
+ if (allowed == null || origin == null) {
response.getHeaders().add(ACCESS_CONTROL_ALLOW_ORIGIN_KEY, ACCESS_CONTROL_ALLOW_ORIGIN_VALUE);
- } else if (allowed.contains(origin)) {
- String originSafe = URLEncoder.encode(origin, StandardCharsets.UTF_8.name());
- response.getHeaders().add(ACCESS_CONTROL_ALLOW_ORIGIN_KEY, originSafe);
+ } else if (allowed.equals(ACCESS_CONTROL_ALLOW_ORIGIN_VALUE) || allowed.contains(origin)) {
+ response.getHeaders().add(ACCESS_CONTROL_ALLOW_ORIGIN_KEY, origin);
}
}
}
diff --git a/src/org/traccar/api/SecurityRequestFilter.java b/src/org/traccar/api/SecurityRequestFilter.java
index 20186b0cb..4c6137ede 100644
--- a/src/org/traccar/api/SecurityRequestFilter.java
+++ b/src/org/traccar/api/SecurityRequestFilter.java
@@ -55,6 +55,11 @@ public class SecurityRequestFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) {
+
+ if (requestContext.getMethod().equals("OPTIONS")) {
+ throw new WebApplicationException(Response.status(Response.Status.OK).build());
+ }
+
SecurityContext securityContext = null;
String authHeader = requestContext.getHeaderString(AUTHORIZATION_HEADER);
diff --git a/src/org/traccar/api/resource/PermissionResource.java b/src/org/traccar/api/resource/DevicePermissionResource.java
index 50deb77c2..f77375cba 100644
--- a/src/org/traccar/api/resource/PermissionResource.java
+++ b/src/org/traccar/api/resource/DevicePermissionResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@ package org.traccar.api.resource;
import org.traccar.Context;
import org.traccar.api.BaseResource;
-import org.traccar.model.Permission;
+import org.traccar.model.DevicePermission;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
@@ -28,13 +28,13 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.sql.SQLException;
-@Path("permissions")
+@Path("permissions/devices")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
-public class PermissionResource extends BaseResource {
+public class DevicePermissionResource extends BaseResource {
@POST
- public Response add(Permission entity) throws SQLException {
+ public Response add(DevicePermission entity) throws SQLException {
Context.getPermissionsManager().checkAdmin(getUserId());
Context.getDataManager().linkDevice(entity.getUserId(), entity.getDeviceId());
Context.getPermissionsManager().refresh();
@@ -42,7 +42,7 @@ public class PermissionResource extends BaseResource {
}
@DELETE
- public Response remove(Permission entity) throws SQLException {
+ public Response remove(DevicePermission entity) throws SQLException {
Context.getPermissionsManager().checkAdmin(getUserId());
Context.getDataManager().unlinkDevice(entity.getUserId(), entity.getDeviceId());
Context.getPermissionsManager().refresh();
diff --git a/src/org/traccar/api/resource/GroupPermissionResource.java b/src/org/traccar/api/resource/GroupPermissionResource.java
new file mode 100644
index 000000000..b8ec4ae3c
--- /dev/null
+++ b/src/org/traccar/api/resource/GroupPermissionResource.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * 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.api.resource;
+
+import org.traccar.Context;
+import org.traccar.api.BaseResource;
+import org.traccar.model.GroupPermission;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.sql.SQLException;
+
+@Path("permissions/groups")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class GroupPermissionResource extends BaseResource {
+
+ @POST
+ public Response add(GroupPermission entity) throws SQLException {
+ Context.getPermissionsManager().checkAdmin(getUserId());
+ Context.getDataManager().linkGroup(entity.getUserId(), entity.getGroupId());
+ Context.getPermissionsManager().refresh();
+ return Response.ok(entity).build();
+ }
+
+ @DELETE
+ public Response remove(GroupPermission entity) throws SQLException {
+ Context.getPermissionsManager().checkAdmin(getUserId());
+ Context.getDataManager().unlinkGroup(entity.getUserId(), entity.getGroupId());
+ Context.getPermissionsManager().refresh();
+ return Response.noContent().build();
+ }
+
+}
diff --git a/src/org/traccar/api/resource/GroupResource.java b/src/org/traccar/api/resource/GroupResource.java
new file mode 100644
index 000000000..49f839499
--- /dev/null
+++ b/src/org/traccar/api/resource/GroupResource.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * 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.api.resource;
+
+import org.traccar.Context;
+import org.traccar.api.BaseResource;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.sql.SQLException;
+import java.util.Collection;
+
+@Path("groups")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class GroupResource extends BaseResource {
+
+ @GET
+ public Collection<Group> get(
+ @QueryParam("all") boolean all, @QueryParam("userId") long userId) throws SQLException {
+ if (all) {
+ Context.getPermissionsManager().checkAdmin(getUserId());
+ return Context.getDataManager().getAllGroups();
+ } else {
+ if (userId == 0) {
+ userId = getUserId();
+ }
+ Context.getPermissionsManager().checkUser(getUserId(), userId);
+ return Context.getDataManager().getGroups(userId);
+ }
+ }
+
+ @POST
+ public Response add(Group entity) throws SQLException {
+ Context.getPermissionsManager().checkReadonly(getUserId());
+ Context.getDataManager().addGroup(entity);
+ Context.getDataManager().linkGroup(getUserId(), entity.getId());
+ Context.getPermissionsManager().refresh();
+ return Response.ok(entity).build();
+ }
+
+ @Path("{id}")
+ @PUT
+ public Response update(@PathParam("id") long id, Group entity) throws SQLException {
+ Context.getPermissionsManager().checkReadonly(getUserId());
+ Context.getPermissionsManager().checkGroup(getUserId(), id);
+ Context.getDataManager().updateGroup(entity);
+ return Response.ok(entity).build();
+ }
+
+ @Path("{id}")
+ @DELETE
+ public Response remove(@PathParam("id") long id) throws SQLException {
+ Context.getPermissionsManager().checkReadonly(getUserId());
+ Context.getPermissionsManager().checkGroup(getUserId(), id);
+ Context.getDataManager().removeGroup(id);
+ Context.getPermissionsManager().refresh();
+ return Response.noContent().build();
+ }
+
+}
diff --git a/src/org/traccar/api/resource/PositionResource.java b/src/org/traccar/api/resource/PositionResource.java
index ec6925b3a..9c174625c 100644
--- a/src/org/traccar/api/resource/PositionResource.java
+++ b/src/org/traccar/api/resource/PositionResource.java
@@ -38,9 +38,14 @@ public class PositionResource extends BaseResource {
public Collection<Position> get(
@QueryParam("deviceId") long deviceId, @QueryParam("from") String from, @QueryParam("to") String to)
throws SQLException {
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- return Context.getDataManager().getPositions(
- deviceId, JsonConverter.parseDate(from), JsonConverter.parseDate(to));
+ if (deviceId == 0) {
+ return Context.getConnectionManager().getInitialState(
+ Context.getPermissionsManager().getDevicePermissions(getUserId()));
+ } else {
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ return Context.getDataManager().getPositions(
+ deviceId, JsonConverter.parseDate(from), JsonConverter.parseDate(to));
+ }
}
}
diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java
index 73984952e..d2da4e701 100644
--- a/src/org/traccar/database/DataManager.java
+++ b/src/org/traccar/database/DataManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2012 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.SQLException;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
@@ -36,10 +37,13 @@ import liquibase.exception.LiquibaseException;
import liquibase.resource.FileSystemResourceAccessor;
import liquibase.resource.ResourceAccessor;
import org.traccar.Config;
+import org.traccar.Context;
import org.traccar.helper.Log;
import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.model.GroupPermission;
import org.traccar.model.MiscFormatter;
-import org.traccar.model.Permission;
+import org.traccar.model.DevicePermission;
import org.traccar.model.Position;
import org.traccar.model.Server;
import org.traccar.model.User;
@@ -53,10 +57,14 @@ public class DataManager implements IdentityManager {
private DataSource dataSource;
+ private final long dataRefreshDelay;
+
private final Map<Long, Device> devicesById = new HashMap<>();
private final Map<String, Device> devicesByUniqueId = new HashMap<>();
private long devicesLastUpdate;
- private final long devicesRefreshDelay;
+
+ private final Map<Long, Group> groupsById = new HashMap<>();
+ private long groupsLastUpdate;
public DataManager(Config config) throws Exception {
this.config = config;
@@ -64,7 +72,7 @@ public class DataManager implements IdentityManager {
initDatabase();
initDatabaseSchema();
- devicesRefreshDelay = config.getLong("database.refreshDelay", DEFAULT_REFRESH_DELAY) * 1000;
+ dataRefreshDelay = config.getLong("database.refreshDelay", DEFAULT_REFRESH_DELAY) * 1000;
}
public DataSource getDataSource() {
@@ -112,7 +120,7 @@ public class DataManager implements IdentityManager {
}
private void updateDeviceCache(boolean force) throws SQLException {
- if (System.currentTimeMillis() - devicesLastUpdate > devicesRefreshDelay || force) {
+ if (System.currentTimeMillis() - devicesLastUpdate > dataRefreshDelay || force) {
devicesById.clear();
devicesByUniqueId.clear();
for (Device device : getAllDevices()) {
@@ -140,6 +148,25 @@ public class DataManager implements IdentityManager {
return devicesByUniqueId.get(uniqueId);
}
+ private void updateGroupCache(boolean force) throws SQLException {
+ if (System.currentTimeMillis() - groupsLastUpdate > dataRefreshDelay || force) {
+ groupsById.clear();
+ for (Group group : getAllGroups()) {
+ groupsById.put(group.getId(), group);
+ }
+ groupsLastUpdate = System.currentTimeMillis();
+ }
+ }
+
+ public Group getGroupById(long id) {
+ try {
+ updateGroupCache(!groupsById.containsKey(id));
+ } catch (SQLException e) {
+ Log.warning(e);
+ }
+ return groupsById.get(id);
+ }
+
private String getQuery(String key) {
String query = config.getString(key);
if (query == null) {
@@ -221,9 +248,14 @@ public class DataManager implements IdentityManager {
.executeUpdate();
}
- public Collection<Permission> getPermissions() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.getPermissionsAll"))
- .executeQuery(Permission.class);
+ public Collection<DevicePermission> getDevicePermissions() throws SQLException {
+ return QueryBuilder.create(dataSource, getQuery("database.selectDevicePermissions"))
+ .executeQuery(DevicePermission.class);
+ }
+
+ public Collection<GroupPermission> getGroupPermissions() throws SQLException {
+ return QueryBuilder.create(dataSource, getQuery("database.selectGroupPermissions"))
+ .executeQuery(GroupPermission.class);
}
public Collection<Device> getAllDevices() throws SQLException {
@@ -232,9 +264,11 @@ public class DataManager implements IdentityManager {
}
public Collection<Device> getDevices(long userId) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectDevices"))
- .setLong("userId", userId)
- .executeQuery(Device.class);
+ Collection<Device> devices = new ArrayList<>();
+ for (long id : Context.getPermissionsManager().getDevicePermissions(userId)) {
+ devices.add(getDeviceById(id));
+ }
+ return devices;
}
public void addDevice(Device device) throws SQLException {
@@ -286,6 +320,51 @@ public class DataManager implements IdentityManager {
AsyncServlet.sessionRefreshUser(userId);
}
+ public Collection<Group> getAllGroups() throws SQLException {
+ return QueryBuilder.create(dataSource, getQuery("database.selectGroupsAll"))
+ .executeQuery(Group.class);
+ }
+
+ public Collection<Group> getGroups(long userId) throws SQLException {
+ Collection<Group> groups = new ArrayList<>();
+ for (long id : Context.getPermissionsManager().getGroupPermissions(userId)) {
+ groups.add(getGroupById(id));
+ }
+ return groups;
+ }
+
+ public void addGroup(Group group) throws SQLException {
+ group.setId(QueryBuilder.create(dataSource, getQuery("database.insertGroup"), true)
+ .setObject(group)
+ .executeUpdate());
+ }
+
+ public void updateGroup(Group group) throws SQLException {
+ QueryBuilder.create(dataSource, getQuery("database.updateGroup"))
+ .setObject(group)
+ .executeUpdate();
+ }
+
+ public void removeGroup(long groupId) throws SQLException {
+ QueryBuilder.create(dataSource, getQuery("database.deleteGroup"))
+ .setLong("id", groupId)
+ .executeUpdate();
+ }
+
+ public void linkGroup(long userId, long groupId) throws SQLException {
+ QueryBuilder.create(dataSource, getQuery("database.linkGroup"))
+ .setLong("userId", userId)
+ .setLong("groupId", groupId)
+ .executeUpdate();
+ }
+
+ public void unlinkGroup(long userId, long groupId) throws SQLException {
+ QueryBuilder.create(dataSource, getQuery("database.unlinkGroup"))
+ .setLong("userId", userId)
+ .setLong("groupId", groupId)
+ .executeUpdate();
+ }
+
public Collection<Position> getPositions(long deviceId, Date from, Date to) throws SQLException {
return QueryBuilder.create(dataSource, getQuery("database.selectPositions"))
.setLong("deviceId", deviceId)
diff --git a/src/org/traccar/database/GroupTree.java b/src/org/traccar/database/GroupTree.java
new file mode 100644
index 000000000..b383b1501
--- /dev/null
+++ b/src/org/traccar/database/GroupTree.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * 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.database;
+
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class GroupTree {
+
+ private static class TreeNode {
+
+ private Group group;
+ private Device device;
+ private Collection<TreeNode> children = new HashSet<>();
+
+ public TreeNode(Group group) {
+ this.group = group;
+ }
+
+ public TreeNode(Device device) {
+ this.device = device;
+ }
+
+ @Override
+ public int hashCode() {
+ if (group != null) {
+ return (int) group.getId();
+ } else {
+ return (int) device.getId();
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof TreeNode)) {
+ return false;
+ }
+ TreeNode other = (TreeNode) obj;
+ if (other == this) {
+ return true;
+ }
+ if (group != null) {
+ if (other.group != null) {
+ return group.getId() == other.group.getId();
+ }
+ } else if (device != null) {
+ if (other.device != null) {
+ return device.getId() == other.device.getId();
+ }
+ }
+ return false;
+ }
+
+ public Group getGroup() {
+ return group;
+ }
+
+ public Device getDevice() {
+ return device;
+ }
+
+ public void setParent(TreeNode parent) {
+ if (parent != null) {
+ parent.children.add(this);
+ }
+ }
+
+ public Collection<TreeNode> getChildren() {
+ return children;
+ }
+
+ }
+
+ private final Map<Long, TreeNode> groupMap = new HashMap<>();
+
+ public GroupTree(Collection<Group> groups, Collection<Device> devices) {
+
+ for (Group group : groups) {
+ groupMap.put(group.getId(), new TreeNode(group));
+ }
+
+ for (TreeNode node : groupMap.values()) {
+ if (node.getGroup().getGroupId() != 0) {
+ node.setParent(groupMap.get(node.getGroup().getGroupId()));
+ }
+ }
+
+ Map<Long, TreeNode> deviceMap = new HashMap<>();
+
+ for (Device device : devices) {
+ deviceMap.put(device.getId(), new TreeNode(device));
+ }
+
+ for (TreeNode node : deviceMap.values()) {
+ if (node.getDevice().getGroupId() != 0) {
+ node.setParent(groupMap.get(node.getDevice().getGroupId()));
+ }
+ }
+
+ }
+
+ public Collection<Group> getGroups(long groupId) {
+ Set<TreeNode> results = new HashSet<>();
+ getNodes(results, groupMap.get(groupId));
+ Collection<Group> groups = new ArrayList<>();
+ for (TreeNode node : results) {
+ if (node.getGroup() != null) {
+ groups.add(node.getGroup());
+ }
+ }
+ return groups;
+ }
+
+ public Collection<Device> getDevices(long groupId) {
+ Set<TreeNode> results = new HashSet<>();
+ getNodes(results, groupMap.get(groupId));
+ Collection<Device> devices = new ArrayList<>();
+ for (TreeNode node : results) {
+ if (node.getDevice() != null) {
+ devices.add(node.getDevice());
+ }
+ }
+ return devices;
+ }
+
+ private void getNodes(Set<TreeNode> results, TreeNode node) {
+ for (TreeNode child : node.getChildren()) {
+ results.add(child);
+ getNodes(results, child);
+ }
+ }
+
+}
diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java
index c676dea23..dc37bbc84 100644
--- a/src/org/traccar/database/PermissionsManager.java
+++ b/src/org/traccar/database/PermissionsManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,13 +16,15 @@
package org.traccar.database;
import java.sql.SQLException;
-import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.traccar.helper.Log;
-import org.traccar.model.Permission;
+import org.traccar.model.Device;
+import org.traccar.model.DevicePermission;
+import org.traccar.model.Group;
+import org.traccar.model.GroupPermission;
import org.traccar.model.Server;
import org.traccar.model.User;
@@ -34,13 +36,21 @@ public class PermissionsManager {
private final Map<Long, User> users = new HashMap<>();
- private final Map<Long, Set<Long>> permissions = new HashMap<>();
+ private final Map<Long, Set<Long>> groupPermissions = new HashMap<>();
+ private final Map<Long, Set<Long>> devicePermissions = new HashMap<>();
- private Set<Long> getPermissions(long userId) {
- if (!permissions.containsKey(userId)) {
- permissions.put(userId, new HashSet<Long>());
+ public Set<Long> getGroupPermissions(long userId) {
+ if (!groupPermissions.containsKey(userId)) {
+ groupPermissions.put(userId, new HashSet<Long>());
}
- return permissions.get(userId);
+ return groupPermissions.get(userId);
+ }
+
+ public Set<Long> getDevicePermissions(long userId) {
+ if (!devicePermissions.containsKey(userId)) {
+ devicePermissions.put(userId, new HashSet<Long>());
+ }
+ return devicePermissions.get(userId);
}
public PermissionsManager(DataManager dataManager) {
@@ -50,15 +60,31 @@ public class PermissionsManager {
public final void refresh() {
users.clear();
- permissions.clear();
+ groupPermissions.clear();
+ devicePermissions.clear();
try {
server = dataManager.getServer();
for (User user : dataManager.getUsers()) {
users.put(user.getId(), user);
}
- for (Permission permission : dataManager.getPermissions()) {
- getPermissions(permission.getUserId()).add(permission.getDeviceId());
+
+ GroupTree groupTree = new GroupTree(dataManager.getAllGroups(), dataManager.getAllDevices());
+ for (GroupPermission permission : dataManager.getGroupPermissions()) {
+ Set<Long> userGroupPermissions = getGroupPermissions(permission.getUserId());
+ Set<Long> userDevicePermissions = getDevicePermissions(permission.getUserId());
+ userGroupPermissions.add(permission.getGroupId());
+ for (Group group : groupTree.getGroups(permission.getGroupId())) {
+ userGroupPermissions.add(group.getId());
+ }
+ for (Device device : groupTree.getDevices(permission.getGroupId())) {
+ userDevicePermissions.add(device.getId());
+ }
+ }
+
+ for (DevicePermission permission : dataManager.getDevicePermissions()) {
+ getDevicePermissions(permission.getUserId()).add(permission.getDeviceId());
}
+
} catch (SQLException error) {
Log.warning(error);
}
@@ -80,12 +106,14 @@ public class PermissionsManager {
}
}
- public Collection<Long> allowedDevices(long userId) {
- return getPermissions(userId);
+ public void checkGroup(long userId, long groupId) throws SecurityException {
+ if (!getGroupPermissions(userId).contains(groupId)) {
+ throw new SecurityException("Group access denied");
+ }
}
public void checkDevice(long userId, long deviceId) throws SecurityException {
- if (!getPermissions(userId).contains(deviceId)) {
+ if (!getDevicePermissions(userId).contains(deviceId)) {
throw new SecurityException("Device access denied");
}
}
diff --git a/src/org/traccar/helper/Checksum.java b/src/org/traccar/helper/Checksum.java
index e6b6cd2c8..c156e53f7 100644
--- a/src/org/traccar/helper/Checksum.java
+++ b/src/org/traccar/helper/Checksum.java
@@ -158,13 +158,20 @@ public final class Checksum {
public static String nmea(String msg) {
int checksum = 0;
- byte[] bytes = msg.getBytes(Charset.defaultCharset());
- for (int i = 1; i < msg.length(); i++) {
- checksum ^= bytes[i];
+ for (byte b : msg.getBytes(Charset.defaultCharset())) {
+ checksum ^= b;
}
return String.format("*%02x", checksum).toUpperCase();
}
+ public static String sum(String msg) {
+ byte checksum = 0;
+ for (byte b : msg.getBytes(Charset.defaultCharset())) {
+ checksum += b;
+ }
+ return String.format("%02X", checksum).toUpperCase();
+ }
+
public static long luhn(long imei) {
long checksum = 0;
long remain = imei;
diff --git a/src/org/traccar/helper/ObdDecoder.java b/src/org/traccar/helper/ObdDecoder.java
index 35fa4dc07..c2d9b1841 100644
--- a/src/org/traccar/helper/ObdDecoder.java
+++ b/src/org/traccar/helper/ObdDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,8 +25,9 @@ public final class ObdDecoder {
private ObdDecoder() {
}
- private static final int MODE_CURRENT = 0x01;
- private static final int MODE_FREEZE_FRAME = 0x02;
+ public static final int MODE_CURRENT = 0x01;
+ public static final int MODE_FREEZE_FRAME = 0x02;
+ public static final int MODE_CODES = 0x03;
private static final int PID_ENGINE_LOAD = 0x04;
private static final int PID_COOLANT_TEMPERATURE = 0x05;
@@ -37,11 +38,13 @@ public final class ObdDecoder {
private static final int PID_FUEL_LEVEL = 0x2F;
private static final int PID_DISTANCE_CLEARED = 0x31;
- public static Map.Entry<String, Object> decode(int mode, int pid, String value) {
+ public static Map.Entry<String, Object> decode(int mode, String value) {
switch (mode) {
case MODE_CURRENT:
case MODE_FREEZE_FRAME:
- return decodeData(pid, value);
+ return decodeData(Integer.parseInt(value.substring(0, 2), 16), value.substring(2));
+ case MODE_CODES:
+ return decodeCodes(value);
default:
return null;
}
@@ -51,6 +54,30 @@ public final class ObdDecoder {
return new AbstractMap.SimpleEntry<>(key, value);
}
+ private static Map.Entry<String, Object> decodeCodes(String value) {
+ StringBuilder codes = new StringBuilder();
+ for (int i = 0; i < value.length() / 4; i++) {
+ int numValue = Integer.parseInt(value.substring(i * 4, (i + 1) * 4), 16);
+ codes.append(',');
+ switch (numValue >> 14) {
+ case 1:
+ codes.append('C');
+ break;
+ case 2:
+ codes.append('B');
+ break;
+ case 3:
+ codes.append('U');
+ break;
+ default:
+ codes.append('P');
+ break;
+ }
+ codes.append(String.format("%04X", numValue & 0x3FFF));
+ }
+ return createEntry("dtcs", codes.toString().replaceFirst(",", ""));
+ }
+
private static Map.Entry<String, Object> decodeData(int pid, String value) {
int intValue = Integer.parseInt(value, 16);
switch (pid) {
@@ -69,7 +96,7 @@ public final class ObdDecoder {
case PID_FUEL_LEVEL:
return createEntry(Event.KEY_FUEL, intValue * 100 / 255);
case PID_DISTANCE_CLEARED:
- return createEntry(Event.KEY_FUEL, intValue);
+ return createEntry("cleared-distance", intValue);
default:
return null;
}
diff --git a/src/org/traccar/helper/Parser.java b/src/org/traccar/helper/Parser.java
index a3f118df0..dcea1c8f7 100644
--- a/src/org/traccar/helper/Parser.java
+++ b/src/org/traccar/helper/Parser.java
@@ -37,12 +37,17 @@ public class Parser {
return matcher.find();
}
+ public void skip(int number) {
+ position += number;
+ }
+
public boolean hasNext() {
return hasNext(1);
}
public boolean hasNext(int number) {
- if (matcher.group(position) != null) {
+ String value = matcher.group(position);
+ if (value != null && !value.isEmpty()) {
return true;
} else {
position += number;
diff --git a/src/org/traccar/model/Device.java b/src/org/traccar/model/Device.java
index 7ca9fc843..934e753b1 100644
--- a/src/org/traccar/model/Device.java
+++ b/src/org/traccar/model/Device.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2012 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -91,4 +91,14 @@ public class Device {
this.positionId = positionId;
}
+ private long groupId;
+
+ public long getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(long groupId) {
+ this.groupId = groupId;
+ }
+
}
diff --git a/src/org/traccar/model/Permission.java b/src/org/traccar/model/DevicePermission.java
index 393de2359..b3bc0cae0 100644
--- a/src/org/traccar/model/Permission.java
+++ b/src/org/traccar/model/DevicePermission.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
*/
package org.traccar.model;
-public class Permission {
+public class DevicePermission {
private long userId;
diff --git a/src/org/traccar/model/Event.java b/src/org/traccar/model/Event.java
index a9f6f9204..221536530 100644
--- a/src/org/traccar/model/Event.java
+++ b/src/org/traccar/model/Event.java
@@ -29,6 +29,7 @@ public abstract class Event extends Extensible {
public static final String KEY_ALARM = "alarm";
public static final String KEY_STATUS = "status";
public static final String KEY_ODOMETER = "odometer";
+ public static final String KEY_HOURS = "hours";
public static final String KEY_INPUT = "input";
public static final String KEY_OUTPUT = "output";
public static final String KEY_POWER = "power";
diff --git a/src/org/traccar/model/Group.java b/src/org/traccar/model/Group.java
new file mode 100644
index 000000000..00f2b2cfc
--- /dev/null
+++ b/src/org/traccar/model/Group.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * 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.model;
+
+public class Group {
+
+ private long id;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ private long groupId;
+
+ public long getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(long groupId) {
+ this.groupId = groupId;
+ }
+
+}
diff --git a/src/org/traccar/model/GroupPermission.java b/src/org/traccar/model/GroupPermission.java
new file mode 100644
index 000000000..9b0011575
--- /dev/null
+++ b/src/org/traccar/model/GroupPermission.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * 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.model;
+
+public class GroupPermission {
+
+ private long userId;
+
+ public long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(long userId) {
+ this.userId = userId;
+ }
+
+ private long groupId;
+
+ public long getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(long groupId) {
+ this.groupId = groupId;
+ }
+
+}
diff --git a/src/org/traccar/protocol/AplicomProtocolDecoder.java b/src/org/traccar/protocol/AplicomProtocolDecoder.java
index 6ae6aa09f..a3d34cf3c 100644
--- a/src/org/traccar/protocol/AplicomProtocolDecoder.java
+++ b/src/org/traccar/protocol/AplicomProtocolDecoder.java
@@ -288,7 +288,7 @@ public class AplicomProtocolDecoder extends BaseProtocolDecoder {
}
if ((selector & 0x0200) != 0) {
- buf.skipBytes(6); // button
+ position.set(Event.KEY_RFID, (((long) buf.readUnsignedShort()) << 32) + buf.readUnsignedInt());
}
if ((selector & 0x0400) != 0) {
diff --git a/src/org/traccar/protocol/AstraProtocol.java b/src/org/traccar/protocol/AstraProtocol.java
new file mode 100644
index 000000000..d0b1d47a5
--- /dev/null
+++ b/src/org/traccar/protocol/AstraProtocol.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder;
+import org.traccar.BaseProtocol;
+import org.traccar.TrackerServer;
+
+import java.util.List;
+
+public class AstraProtocol extends BaseProtocol {
+
+ public AstraProtocol() {
+ super("astra");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ServerBootstrap(), this.getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 1, 2, -3, 0));
+ pipeline.addLast("objectDecoder", new AstraProtocolDecoder(AstraProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/AstraProtocolDecoder.java b/src/org/traccar/protocol/AstraProtocolDecoder.java
new file mode 100644
index 000000000..8cfec95fe
--- /dev/null
+++ b/src/org/traccar/protocol/AstraProtocolDecoder.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * 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.traccar.BaseProtocolDecoder;
+import org.traccar.helper.BitUtil;
+import org.traccar.helper.DateBuilder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.nio.charset.Charset;
+import java.util.LinkedList;
+import java.util.List;
+
+public class AstraProtocolDecoder extends BaseProtocolDecoder {
+
+ public AstraProtocolDecoder(AstraProtocol protocol) {
+ super(protocol);
+ }
+
+ public static final int MSG_HEARTBEAT = 0x1A;
+ public static final int MSG_DATA = 0x10;
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ChannelBuffer buf = (ChannelBuffer) msg;
+
+ if (channel != null) {
+ channel.write(ChannelBuffers.wrappedBuffer(new byte[] {0x06}), remoteAddress);
+ }
+
+ buf.readUnsignedByte(); // protocol
+ buf.readUnsignedShort(); // length
+
+ String imei = String.format("%08d", buf.readUnsignedInt()) + String.format("%07d", buf.readUnsignedMedium());
+ if (!identify(imei, channel, remoteAddress)) {
+ return null;
+ }
+
+ List<Position> positions = new LinkedList<>();
+
+ while (buf.readableBytes() > 2) {
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(getDeviceId());
+
+ buf.readUnsignedByte(); // index
+
+ position.setLatitude(buf.readInt() * 0.000001);
+ position.setLongitude(buf.readInt() * 0.000001);
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(1980, 1, 6).addMillis(buf.readUnsignedInt() * 1000L);
+ position.setTime(dateBuilder.getDate());
+
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte() * 2));
+ position.setCourse(buf.readUnsignedByte() * 2);
+
+ int reason = buf.readUnsignedMedium();
+ buf.readUnsignedShort(); // status
+
+ position.set(Event.PREFIX_IO + 1, buf.readUnsignedByte());
+ position.set(Event.PREFIX_ADC + 1, buf.readUnsignedByte());
+ position.set(Event.KEY_BATTERY, buf.readUnsignedByte());
+ position.set(Event.KEY_POWER, buf.readUnsignedByte());
+
+ buf.readUnsignedByte(); // max journey speed
+ buf.skipBytes(6); // accelerometer
+ buf.readUnsignedShort(); // journey distance
+ buf.readUnsignedShort(); // journey idle time
+
+ position.setAltitude(buf.readUnsignedByte() * 20);
+
+ int quality = buf.readUnsignedByte();
+ position.set(Event.KEY_SATELLITES, quality & 0xf);
+ position.set(Event.KEY_GSM, quality >> 4);
+
+ buf.readUnsignedByte(); // geofence events
+
+ if (BitUtil.check(reason, 6) || BitUtil.check(reason, 7)) {
+
+ position.set(Event.KEY_RFID, buf.readBytes(7).toString(Charset.defaultCharset()));
+ position.set(Event.KEY_ODOMETER, buf.readUnsignedMedium());
+
+ buf.readUnsignedShort(); // engine time
+
+ }
+
+ // extra data
+
+ positions.add(position);
+
+ }
+
+ return positions;
+ }
+
+}
diff --git a/src/org/traccar/protocol/BoxProtocol.java b/src/org/traccar/protocol/BoxProtocol.java
index ae8207002..33cfca282 100644
--- a/src/org/traccar/protocol/BoxProtocol.java
+++ b/src/org/traccar/protocol/BoxProtocol.java
@@ -37,8 +37,8 @@ public class BoxProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, '\r'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new BoxProtocolDecoder(BoxProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/CarscopProtocol.java b/src/org/traccar/protocol/CarscopProtocol.java
index 1ac3e5e9f..4432fb87a 100644
--- a/src/org/traccar/protocol/CarscopProtocol.java
+++ b/src/org/traccar/protocol/CarscopProtocol.java
@@ -37,8 +37,8 @@ public class CarscopProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, '^'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new CarscopProtocolDecoder(CarscopProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/CastelProtocolDecoder.java b/src/org/traccar/protocol/CastelProtocolDecoder.java
index 3179cbd78..9f332dd04 100644
--- a/src/org/traccar/protocol/CastelProtocolDecoder.java
+++ b/src/org/traccar/protocol/CastelProtocolDecoder.java
@@ -109,6 +109,28 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder {
}
}
+ private void sendResponse(
+ Channel channel, SocketAddress remoteAddress, ChannelBuffer id, short type) {
+
+ if (channel != null) {
+ int length = 2 + 2 + id.readableBytes() + 2 + 4 + 8 + 2 + 2;
+
+ ChannelBuffer response = ChannelBuffers.directBuffer(ByteOrder.LITTLE_ENDIAN, length);
+ response.writeByte('@'); response.writeByte('@');
+ response.writeShort(length);
+ response.writeBytes(id);
+ response.writeShort(ChannelBuffers.swapShort(type));
+ response.writeInt(0);
+ for (int i = 0; i < 8; i++) {
+ response.writeByte(0xff);
+ }
+ response.writeShort(
+ Checksum.crc16(Checksum.CRC16_X25, response.toByteBuffer(0, response.writerIndex())));
+ response.writeByte(0x0D); response.writeByte(0x0A);
+ channel.write(response, remoteAddress);
+ }
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -134,23 +156,7 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder {
if (type == 0x2001) {
- if (channel != null) {
- int length = 2 + 2 + id.readableBytes() + 2 + 4 + 8 + 2 + 2;
-
- ChannelBuffer response = ChannelBuffers.directBuffer(ByteOrder.LITTLE_ENDIAN, length);
- response.writeByte('@'); response.writeByte('@');
- response.writeShort(length);
- response.writeBytes(id);
- response.writeShort(ChannelBuffers.swapShort((short) 0x1001));
- response.writeInt(0);
- for (int i = 0; i < 8; i++) {
- response.writeByte(0xff);
- }
- response.writeShort(
- Checksum.crc16(Checksum.CRC16_X25, response.toByteBuffer(0, response.writerIndex())));
- response.writeByte(0x0D); response.writeByte(0x0A);
- channel.write(response, remoteAddress);
- }
+ sendResponse(channel, remoteAddress, id, (short) 0x1001);
buf.readUnsignedInt(); // index
buf.readUnsignedInt(); // unix time
diff --git a/src/org/traccar/protocol/CityeasyProtocol.java b/src/org/traccar/protocol/CityeasyProtocol.java
index 1049e48eb..82302d2d7 100644
--- a/src/org/traccar/protocol/CityeasyProtocol.java
+++ b/src/org/traccar/protocol/CityeasyProtocol.java
@@ -41,8 +41,8 @@ public class CityeasyProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0));
- pipeline.addLast("objectDecoder", new CityeasyProtocolDecoder(CityeasyProtocol.this));
pipeline.addLast("objectEncoder", new CityeasyProtocolEncoder());
+ pipeline.addLast("objectDecoder", new CityeasyProtocolDecoder(CityeasyProtocol.this));
}
});
}
diff --git a/src/org/traccar/protocol/FlextrackProtocol.java b/src/org/traccar/protocol/FlextrackProtocol.java
index 0d1b13d8a..3b1aaa3d8 100644
--- a/src/org/traccar/protocol/FlextrackProtocol.java
+++ b/src/org/traccar/protocol/FlextrackProtocol.java
@@ -36,8 +36,8 @@ public class FlextrackProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, "\r"));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new FlextrackProtocolDecoder(FlextrackProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/Gl100Protocol.java b/src/org/traccar/protocol/Gl100Protocol.java
index cc2c826ab..f51834ea2 100644
--- a/src/org/traccar/protocol/Gl100Protocol.java
+++ b/src/org/traccar/protocol/Gl100Protocol.java
@@ -38,16 +38,16 @@ public class Gl100Protocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, '\0'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new Gl100ProtocolDecoder(Gl100Protocol.this));
}
});
serverList.add(new TrackerServer(new ConnectionlessBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new Gl100ProtocolDecoder(Gl100Protocol.this));
}
});
diff --git a/src/org/traccar/protocol/Gl200Protocol.java b/src/org/traccar/protocol/Gl200Protocol.java
index 3aa69567d..701652e12 100644
--- a/src/org/traccar/protocol/Gl200Protocol.java
+++ b/src/org/traccar/protocol/Gl200Protocol.java
@@ -44,19 +44,19 @@ public class Gl200Protocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, "$", "\0"));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
- pipeline.addLast("objectDecoder", new Gl200ProtocolDecoder(Gl200Protocol.this));
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectEncoder", new Gl200ProtocolEncoder());
+ pipeline.addLast("objectDecoder", new Gl200ProtocolDecoder(Gl200Protocol.this));
}
});
serverList.add(new TrackerServer(new ConnectionlessBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
- pipeline.addLast("objectDecoder", new Gl200ProtocolDecoder(Gl200Protocol.this));
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectEncoder", new Gl200ProtocolEncoder());
+ pipeline.addLast("objectDecoder", new Gl200ProtocolDecoder(Gl200Protocol.this));
}
});
}
diff --git a/src/org/traccar/protocol/Gl200ProtocolDecoder.java b/src/org/traccar/protocol/Gl200ProtocolDecoder.java
index e4bf43979..574f9a8c3 100644
--- a/src/org/traccar/protocol/Gl200ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gl200ProtocolDecoder.java
@@ -16,10 +16,13 @@
package org.traccar.protocol;
import java.net.SocketAddress;
+import java.util.LinkedList;
import java.util.regex.Pattern;
+
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.Context;
+import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -33,7 +36,7 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN_HEARTBEAT = new PatternBuilder()
+ private static final Pattern PATTERN_HBD = new PatternBuilder()
.text("+ACK:GTHBD,")
.number("([0-9A-Z]{2}xxxx),")
.any().text(",")
@@ -68,115 +71,204 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
.text("$").optional()
.compile();
- private static final Pattern PATTERN = new PatternBuilder()
+ private static final Pattern PATTERN_LOCATION = new PatternBuilder()
+ .number("(?:d{1,2})?,") // gps accuracy
+ .number("(d{1,3}.d)?,") // speed
+ .number("(d{1,3})?,") // course
+ .number("(-?d{1,5}.d)?,") // altitude
+ .number("(-?d{1,3}.d{6})?,") // longitude
+ .number("(-?d{1,2}.d{6})?,") // latitude
+ .number("(dddd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd)").optional(2) // time
+ .text(",")
.groupBegin()
- .text("+").expression("(?:RESP|BUFF)").text(":")
+ .number("(0ddd)?,") // mcc
+ .number("(0ddd)?,") // mnc
+ .number("(xxxx)?,") // lac
+ .number("(xxxx)?,") // cell
.or()
- .binary("00?04,")
- .number("xxxx,")
- .expression("[01],")
+ .number("(d+)?,") // mcc
+ .number("(d+)?,") // mnc
+ .number("(d+)?,") // lac
+ .number("(d+)?,") // cell
.groupEnd()
- .expression("GT...,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .expression("([^,]+),") // imei
+ .number("(?:d+|(d+.d))?,") // odometer
+ .compile();
- .groupBegin()
- .expression("[0-9A-Z]{17},") // vin
+ private static final Pattern PATTERN_OBD = new PatternBuilder()
+ .text("+RESP:GTOBD,")
+ .number("[0-9A-Z]{2}xxxx,") // protocol version
+ .number("(d{15}),") // imei
+ .expression("(?:[0-9A-Z]{17})?,") // vin
.expression("[^,]{0,20},") // device name
.expression("[01],") // report type
.number("x{1,8},") // report mask
- .expression("[0-9A-Z]{17},") // vin
+ .expression("(?:[0-9A-Z]{17})?,") // vin
.number("[01],") // obd connect
- .number("d{1,5},") // obd voltage
- .number("x{8},") // support pids
- .number("(d{1,5}),") // engine rpm
- .number("(d{1,3}),") // speed
- .number("(-?d{1,3}),") // coolant temp
+ .number("(?:d{1,5})?,") // obd voltage
+ .number("(?:x{8})?,") // support pids
+ .number("(d{1,5})?,") // engine rpm
+ .number("(d{1,3})?,") // speed
+ .number("(-?d{1,3})?,") // coolant temp
.number("(d+.?d*|Inf|NaN)?,") // fuel consumption
- .number("(d{1,5}),") // dtcs cleared distance
- .number("d{1,5},")
- .expression("([01]),") // obd connect
- .number("(d{1,3}),") // number of dtcs
+ .number("(d{1,5})?,") // dtcs cleared distance
+ .number("(?:d{1,5})?,")
+ .expression("([01])?,") // obd connect
+ .number("(d{1,3})?,") // number of dtcs
.number("(x*),") // dtcs
- .number("(d{1,3}),") // throttle
- .number("d{1,3},") // engine load
+ .number("(d{1,3})?,") // throttle
+ .number("(?:d{1,3})?,") // engine load
.number("(d{1,3})?,") // fuel level
- .number("(d+)") // odometer
- .or().any()
- .groupEnd().text(",")
-
- .number("(d{1,2})?,") // gps accuracy
- .number("(d{1,3}.d)?,") // speed
- .number("(d{1,3})?,") // course
- .number("(-?d{1,5}.d)?,") // altitude
- .number("(-?d{1,3}.d{6})?,") // longitude
- .number("(-?d{1,2}.d{6})?,") // latitude
+ .number("(d+),") // odometer
+ .expression(PATTERN_LOCATION.pattern())
+ .number("(d{1,7}.d)?,") // odometer
.number("(dddd)(dd)(dd)") // date
.number("(dd)(dd)(dd)").optional(2) // time
.text(",")
- .number("(0ddd)?,") // mcc
- .number("(0ddd)?,") // mnc
- .number("(?:xxxx)?")
- .number("(xxxx)").optional(2) // lac
- .text(",")
- .number("(xxxx)?,") // cell
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
+ private static final Pattern PATTERN_FRI = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF):GTFRI,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("(d+)?,") // power
+ .number("d{1,2},") // report type
+ .number("d{1,2},") // count
+ .expression("((?:")
+ .expression(PATTERN_LOCATION.pattern())
+ .expression(")+)")
.groupBegin()
- .number("(d+.d)?,") // odometer
+ .number("(d{1,7}.d)?,").optional() // odometer
.number("(d{1,3})?,") // battery
- .groupEnd("?")
+ .or()
+ .number("(d{1,7}.d)?,") // odometer
+ .number("(d{5}:dd:dd)?,") // hour meter
+ .number("(x+)?,") // adc 1
+ .number("(x+)?,") // adc 2
+ .number("(d{1,3})?,") // battery
+ .number("(?:(xx)(xx)(xx))?,,,,") // device status
+ .groupEnd()
+ .number("(dddd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd)").optional(2) // time
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF):GT...,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}),") // imei
+ .expression("[^,]*,") // device name
+ .number("d*,")
+ .number("d{1,2},") // report type
+ .number("d{1,2},") // count
+ .expression(PATTERN_LOCATION.pattern())
.groupBegin()
+ .number("(d{1,7}.d)?,").optional() // odometer
+ .number("(d{1,3})?,") // battery
+ .or()
+ .number("(d{1,7}.d)?,") // odometer
+ .groupEnd()
+ .number("(dddd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd)").optional(2) // time
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
+ private static final Pattern PATTERN_BASIC = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF)").text(":")
+ .expression("GT...,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
.any()
+ .number("(d{1,3}.d)?,") // speed
+ .number("(d{1,3})?,") // course
+ .number("(-?d{1,5}.d)?,") // altitude
+ .number("(-?d{1,3}.d{6}),") // longitude
+ .number("(-?d{1,2}.d{6}),") // latitude
.number("(dddd)(dd)(dd)") // date
.number("(dd)(dd)(dd)") // time
- .or()
+ .text(",")
.any()
- .groupEnd()
- .number(",(xxxx)")
+ .number("(xxxx)") // count number
.text("$").optional()
.compile();
- @Override
- protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+ private Object decodeHbd(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_HBD, sentence);
+ if (parser.matches() && channel != null) {
+ channel.write("+SACK:GTHBD," + parser.next() + "," + parser.next() + "$", remoteAddress);
+ }
+ return null;
+ }
- String sentence = (String) msg;
+ private Object decodeInf(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_INF, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
- Parser parser = new Parser(PATTERN_HEARTBEAT, sentence);
- if (parser.matches()) {
- if (channel != null) {
- channel.write("+SACK:GTHBD," + parser.next() + "," + parser.next() + "$", remoteAddress);
- }
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+
+ if (!identify(parser.next(), channel, remoteAddress)) {
return null;
}
+ position.setDeviceId(getDeviceId());
- parser = new Parser(PATTERN_INF, sentence);
- if (parser.matches()) {
+ position.set(Event.KEY_STATUS, parser.next());
+ position.set(Event.KEY_POWER, parser.next());
+ position.set(Event.KEY_BATTERY, parser.next());
+ position.set(Event.KEY_CHARGE, parser.next());
- Position position = new Position();
- position.setProtocol(getProtocolName());
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
- if (!identify(parser.next(), channel, remoteAddress)) {
- return null;
- }
- position.setDeviceId(getDeviceId());
+ getLastLocation(position, dateBuilder.getDate());
+
+ position.set(Event.KEY_INDEX, parser.next());
- position.set(Event.KEY_STATUS, parser.next());
- position.set(Event.KEY_POWER, parser.next());
- position.set(Event.KEY_BATTERY, parser.next());
- position.set(Event.KEY_CHARGE, parser.next());
+ return position;
+ }
+
+ private void decodeLocation(Position position, Parser parser) {
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
+ position.setAltitude(parser.nextDouble());
+
+ if (parser.hasNext(8)) {
+ position.setValid(true);
+ position.setLongitude(parser.nextDouble());
+ position.setLatitude(parser.nextDouble());
DateBuilder dateBuilder = new DateBuilder()
.setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
.setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+ } else {
+ getLastLocation(position, null);
+ }
- getLastLocation(position, dateBuilder.getDate());
+ if (parser.hasNext(4)) {
+ position.set(Event.KEY_MCC, parser.nextInt());
+ position.set(Event.KEY_MNC, parser.nextInt());
+ position.set(Event.KEY_LAC, parser.nextInt(16));
+ position.set(Event.KEY_CID, parser.nextInt(16));
+ }
- position.set(Event.KEY_INDEX, parser.next());
+ parser.skip(4); // alternative networks
- return position;
- }
+ position.set(Event.KEY_ODOMETER, parser.next());
+ }
- parser = new Parser(PATTERN, sentence);
+ private Object decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_OBD, sentence);
if (!parser.matches()) {
return null;
}
@@ -189,12 +281,6 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
}
position.setDeviceId(getDeviceId());
- // RFID
- if (sentence.startsWith("+RESP:GTIDA")) {
- position.set(Event.KEY_RFID, sentence.split(",")[5]);
- }
-
- // OBD
position.set(Event.KEY_RPM, parser.next());
position.set(Event.KEY_OBD_SPEED, parser.next());
position.set(Event.PREFIX_TEMP + 1, parser.next());
@@ -207,32 +293,111 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
position.set(Event.KEY_FUEL, parser.next());
position.set(Event.KEY_OBD_ODOMETER, parser.next());
- if (parser.hasNext(12)) {
- position.setValid(parser.nextInt() < 20);
- position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
- position.setCourse(parser.nextDouble());
- position.setAltitude(parser.nextDouble());
- position.setLongitude(parser.nextDouble());
- position.setLatitude(parser.nextDouble());
+ decodeLocation(position, parser);
+ position.set(Event.KEY_ODOMETER, parser.next());
+
+ if (parser.hasNext(6)) {
DateBuilder dateBuilder = new DateBuilder()
.setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
.setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
- position.setTime(dateBuilder.getDate());
- } else {
- getLastLocation(position, null);
+ if (!position.getOutdated() && position.getFixTime().after(dateBuilder.getDate())) {
+ position.setTime(dateBuilder.getDate());
+ }
}
- if (parser.hasNext(4)) {
- position.set(Event.KEY_MCC, parser.nextInt());
- position.set(Event.KEY_MNC, parser.nextInt());
- position.set(Event.KEY_LAC, parser.nextInt(16));
- position.set(Event.KEY_CID, parser.nextInt(16));
+ return position;
+ }
+
+ private Object decodeFri(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_FRI, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ LinkedList<Position> positions = new LinkedList<>();
+
+ if (!identify(parser.next(), channel, remoteAddress)) {
+ return null;
+ }
+
+ int power = parser.nextInt();
+
+ Parser itemParser = new Parser(PATTERN_LOCATION, parser.next());
+ while (itemParser.find()) {
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(getDeviceId());
+
+ decodeLocation(position, itemParser);
+
+ positions.add(position);
+ }
+
+ Position position = positions.getLast();
+
+ decodeLocation(position, parser);
+
+ // power value only on some devices
+ if (power > 10) {
+ position.set(Event.KEY_POWER, power);
}
position.set(Event.KEY_ODOMETER, parser.next());
position.set(Event.KEY_BATTERY, parser.next());
+ position.set(Event.KEY_ODOMETER, parser.next());
+ position.set(Event.KEY_HOURS, parser.next());
+ position.set(Event.PREFIX_ADC + 1, parser.next());
+ position.set(Event.PREFIX_ADC + 2, parser.next());
+ position.set(Event.KEY_BATTERY, parser.next());
+
+ if (parser.hasNext(3)) {
+ int ignition = parser.nextInt(16);
+ if (BitUtil.check(ignition, 4)) {
+ position.set(Event.KEY_IGNITION, false);
+ } else if (BitUtil.check(ignition, 5)) {
+ position.set(Event.KEY_IGNITION, true);
+ }
+ position.set(Event.KEY_INPUT, parser.nextInt(16));
+ position.set(Event.KEY_OUTPUT, parser.nextInt(16));
+ }
+
+ // workaround for wrong location time
+ if (parser.hasNext(6)) {
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ if (!position.getOutdated() && position.getFixTime().after(dateBuilder.getDate())) {
+ position.setTime(dateBuilder.getDate());
+ }
+ }
+
+ return positions;
+ }
+
+ private Object decodeOther(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+
+ if (!identify(parser.next(), channel, remoteAddress)) {
+ return null;
+ }
+ position.setDeviceId(getDeviceId());
+
+ decodeLocation(position, parser);
+
+ position.set(Event.KEY_ODOMETER, parser.next());
+ position.set(Event.KEY_BATTERY, parser.next());
+
+ position.set(Event.KEY_ODOMETER, parser.next());
+
+ // workaround for wrong location time
if (parser.hasNext(6)) {
DateBuilder dateBuilder = new DateBuilder()
.setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
@@ -249,4 +414,71 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Object decodeBasic(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_BASIC, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+
+ if (!identify(parser.next(), channel, remoteAddress)) {
+ return null;
+ }
+ position.setDeviceId(getDeviceId());
+
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
+ position.setAltitude(parser.nextDouble());
+
+ position.setValid(true);
+ position.setLongitude(parser.nextDouble());
+ position.setLatitude(parser.nextDouble());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+
+ return position;
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ String sentence = (String) msg;
+
+ int typeIndex = sentence.indexOf(":GT");
+ if (typeIndex < 0) {
+ return null;
+ }
+
+ Object result;
+ switch (sentence.substring(typeIndex + 3, typeIndex + 6)) {
+ case "HBD":
+ result = decodeHbd(channel, remoteAddress, sentence);
+ break;
+ case "INF":
+ result = decodeInf(channel, remoteAddress, sentence);
+ break;
+ case "OBD":
+ result = decodeObd(channel, remoteAddress, sentence);
+ break;
+ case "FRI":
+ result = decodeFri(channel, remoteAddress, sentence);
+ break;
+ default:
+ result = decodeOther(channel, remoteAddress, sentence);
+ break;
+ }
+
+ if (result == null) {
+ result = decodeBasic(channel, remoteAddress, sentence);
+ }
+
+ return result;
+ }
+
}
diff --git a/src/org/traccar/protocol/GlobalSatProtocol.java b/src/org/traccar/protocol/GlobalSatProtocol.java
index 10db8e313..592ba152e 100644
--- a/src/org/traccar/protocol/GlobalSatProtocol.java
+++ b/src/org/traccar/protocol/GlobalSatProtocol.java
@@ -37,8 +37,8 @@ public class GlobalSatProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, '!'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new GlobalSatProtocolDecoder(GlobalSatProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/GoSafeProtocol.java b/src/org/traccar/protocol/GoSafeProtocol.java
index af2c2858d..bc1ed14de 100644
--- a/src/org/traccar/protocol/GoSafeProtocol.java
+++ b/src/org/traccar/protocol/GoSafeProtocol.java
@@ -36,8 +36,8 @@ public class GoSafeProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, '#'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new GoSafeProtocolDecoder(GoSafeProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/Gps103Protocol.java b/src/org/traccar/protocol/Gps103Protocol.java
index 6ddc2dea1..d8ad0a8b7 100644
--- a/src/org/traccar/protocol/Gps103Protocol.java
+++ b/src/org/traccar/protocol/Gps103Protocol.java
@@ -47,19 +47,19 @@ public class Gps103Protocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, "\r\n", "\n", ";"));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
- pipeline.addLast("objectDecoder", new Gps103ProtocolDecoder(Gps103Protocol.this));
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectEncoder", new Gps103ProtocolEncoder());
+ pipeline.addLast("objectDecoder", new Gps103ProtocolDecoder(Gps103Protocol.this));
}
});
serverList.add(new TrackerServer(new ConnectionlessBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
- pipeline.addLast("objectDecoder", new Gps103ProtocolDecoder(Gps103Protocol.this));
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectEncoder", new Gps103ProtocolEncoder());
+ pipeline.addLast("objectDecoder", new Gps103ProtocolDecoder(Gps103Protocol.this));
}
});
}
diff --git a/src/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/org/traccar/protocol/Gps103ProtocolDecoder.java
index a45e20ba2..e2aed6309 100644
--- a/src/org/traccar/protocol/Gps103ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gps103ProtocolDecoder.java
@@ -118,11 +118,16 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
}
// Send response #2
- if (sentence.length() == 15 && Character.isDigit(sentence.charAt(0))) {
+ if (Character.isDigit(sentence.charAt(0))) {
if (channel != null) {
channel.write("ON", remoteAddress);
}
- return null;
+ int start = sentence.indexOf("imei:");
+ if (start >= 0) {
+ sentence = sentence.substring(start);
+ } else {
+ return null;
+ }
}
Position position = new Position();
diff --git a/src/org/traccar/protocol/GpsGateProtocol.java b/src/org/traccar/protocol/GpsGateProtocol.java
index 9f07550e4..c654810b1 100644
--- a/src/org/traccar/protocol/GpsGateProtocol.java
+++ b/src/org/traccar/protocol/GpsGateProtocol.java
@@ -37,8 +37,8 @@ public class GpsGateProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new GpsGateProtocolDecoder(GpsGateProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/GpsGateProtocolDecoder.java b/src/org/traccar/protocol/GpsGateProtocolDecoder.java
index 421dc5304..b48fa6266 100644
--- a/src/org/traccar/protocol/GpsGateProtocolDecoder.java
+++ b/src/org/traccar/protocol/GpsGateProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2013 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@ package org.traccar.protocol;
import java.net.SocketAddress;
import java.util.regex.Pattern;
+
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.helper.Checksum;
@@ -31,7 +32,7 @@ public class GpsGateProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = new PatternBuilder()
+ private static final Pattern PATTERN_GPRMC = new PatternBuilder()
.text("$GPRMC,")
.number("(dd)(dd)(dd).?(d+)?,") // time
.expression("([AV]),") // validity
@@ -45,6 +46,24 @@ public class GpsGateProtocolDecoder extends BaseProtocolDecoder {
.any()
.compile();
+ private static final Pattern PATTERN_FRCMD = new PatternBuilder()
+ .text("$FRCMD,")
+ .number("(d+),") // imei
+ .expression("[^,]*,") // command
+ .expression("[^,]*,")
+ .number("(dd)(dd.d+),") // latitude
+ .expression("([NS]),")
+ .number("(ddd)(dd.d+),") // longitude
+ .expression("([EW]),")
+ .number("(d+.?d*),") // altitude
+ .number("(d+.?d*),") // speed
+ .number("(d+.?d*),") // course
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .number("(dd)(dd)(dd).?(d+)?,") // time
+ .expression("([01]),") // validity
+ .any()
+ .compile();
+
private void send(Channel channel, String message) {
if (channel != null) {
channel.write(message + Checksum.nmea(message) + "\r\n");
@@ -85,10 +104,10 @@ public class GpsGateProtocolDecoder extends BaseProtocolDecoder {
// Version check
send(channel, "$FRVER,1,0,GpsGate Server 1.0");
- } else if (sentence.startsWith("$GPRMC,") && hasDeviceId()) {
+ } else if (sentence.startsWith("$GPRMC,")) {
- Parser parser = new Parser(PATTERN, sentence);
- if (!parser.matches()) {
+ Parser parser = new Parser(PATTERN_GPRMC, sentence);
+ if (!parser.matches() || !hasDeviceId()) {
return null;
}
@@ -109,6 +128,37 @@ public class GpsGateProtocolDecoder extends BaseProtocolDecoder {
position.setTime(dateBuilder.getDate());
return position;
+
+ } else if (sentence.startsWith("$FRCMD,")) {
+
+ Parser parser = new Parser(PATTERN_FRCMD, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+
+ if (!identify(parser.next(), channel, remoteAddress)) {
+ return null;
+ }
+ position.setDeviceId(getDeviceId());
+
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setAltitude(parser.nextDouble());
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+
+ position.setValid(parser.next().equals("1"));
+
+ return position;
+
}
return null;
diff --git a/src/org/traccar/protocol/GpsmtaProtocol.java b/src/org/traccar/protocol/GpsmtaProtocol.java
index fe586644a..d1eaa2fd3 100644
--- a/src/org/traccar/protocol/GpsmtaProtocol.java
+++ b/src/org/traccar/protocol/GpsmtaProtocol.java
@@ -35,8 +35,8 @@ public class GpsmtaProtocol extends BaseProtocol {
serverList.add(new TrackerServer(new ConnectionlessBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new GpsmtaProtocolDecoder(GpsmtaProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/Gt06FrameDecoder.java b/src/org/traccar/protocol/Gt06FrameDecoder.java
index ed0d8d548..67f42efb4 100644
--- a/src/org/traccar/protocol/Gt06FrameDecoder.java
+++ b/src/org/traccar/protocol/Gt06FrameDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2014 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,9 +24,7 @@ public class Gt06FrameDecoder extends FrameDecoder {
@Override
protected Object decode(
- ChannelHandlerContext ctx,
- Channel channel,
- ChannelBuffer buf) throws Exception {
+ ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception {
// Check minimum length
if (buf.readableBytes() < 5) {
@@ -37,6 +35,12 @@ public class Gt06FrameDecoder extends FrameDecoder {
if (buf.getByte(buf.readerIndex()) == 0x78) {
length += 1 + buf.getUnsignedByte(buf.readerIndex() + 2);
+
+ int type = buf.getUnsignedByte(buf.readerIndex() + 3);
+ if (type == Gt06ProtocolDecoder.MSG_STATUS && length == 13) {
+ length += 2; // workaround for #1727
+ }
+
} else {
length += 2 + buf.getUnsignedShort(buf.readerIndex() + 2);
}
diff --git a/src/org/traccar/protocol/Gt06Protocol.java b/src/org/traccar/protocol/Gt06Protocol.java
index eac9ad71a..4630342a5 100644
--- a/src/org/traccar/protocol/Gt06Protocol.java
+++ b/src/org/traccar/protocol/Gt06Protocol.java
@@ -37,8 +37,8 @@ public class Gt06Protocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new Gt06FrameDecoder());
- pipeline.addLast("objectDecoder", new Gt06ProtocolDecoder(Gt06Protocol.this));
pipeline.addLast("objectEncoder", new Gt06ProtocolEncoder());
+ pipeline.addLast("objectDecoder", new Gt06ProtocolDecoder(Gt06Protocol.this));
}
});
}
diff --git a/src/org/traccar/protocol/HomtecsProtocol.java b/src/org/traccar/protocol/HomtecsProtocol.java
new file mode 100644
index 000000000..1a2e98565
--- /dev/null
+++ b/src/org/traccar/protocol/HomtecsProtocol.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * 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.ConnectionlessBootstrap;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.handler.codec.string.StringDecoder;
+import org.traccar.BaseProtocol;
+import org.traccar.TrackerServer;
+
+import java.util.List;
+
+public class HomtecsProtocol extends BaseProtocol {
+
+ public HomtecsProtocol() {
+ super("homtecs");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ConnectionlessBootstrap(), this.getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("stringDecoder", new StringDecoder());
+ pipeline.addLast("objectDecoder", new HomtecsProtocolDecoder(HomtecsProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/HomtecsProtocolDecoder.java b/src/org/traccar/protocol/HomtecsProtocolDecoder.java
new file mode 100644
index 000000000..0b1cd99e9
--- /dev/null
+++ b/src/org/traccar/protocol/HomtecsProtocolDecoder.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.helper.DateBuilder;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+public class HomtecsProtocolDecoder extends BaseProtocolDecoder {
+
+ public HomtecsProtocolDecoder(HomtecsProtocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .expression("([^,]+),") // id
+ .number("(dd)(dd)(dd),") // date
+ .number("(dd)(dd)(dd).(d+),") // time
+ .number("(d+),") // satellites
+ .number("(dd)(dd.d+),") // latitude
+ .expression("([NS]),")
+ .number("(ddd)(dd.d+),") // longitude
+ .expression("([EW]),")
+ .number("(d+.?d*)?,") // speed
+ .number("(d+.?d*)?,") // course
+ .any()
+ .compile();
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ Parser parser = new Parser(PATTERN, (String) msg);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+
+ if (!identify(parser.next(), channel, remoteAddress)) {
+ return null;
+ }
+ position.setDeviceId(getDeviceId());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt());
+
+ position.setTime(dateBuilder.getDate());
+
+ position.setValid(true);
+ position.set(Event.KEY_SATELLITES, parser.nextInt());
+
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
+
+ return position;
+ }
+
+}
diff --git a/src/org/traccar/protocol/IntellitracProtocol.java b/src/org/traccar/protocol/IntellitracProtocol.java
index c06585547..a6caf770f 100644
--- a/src/org/traccar/protocol/IntellitracProtocol.java
+++ b/src/org/traccar/protocol/IntellitracProtocol.java
@@ -36,8 +36,8 @@ public class IntellitracProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new IntellitracFrameDecoder(1024));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new IntellitracProtocolDecoder(IntellitracProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/KenjiProtocolDecoder.java b/src/org/traccar/protocol/KenjiProtocolDecoder.java
index e1f8130fa..e190af948 100755
--- a/src/org/traccar/protocol/KenjiProtocolDecoder.java
+++ b/src/org/traccar/protocol/KenjiProtocolDecoder.java
@@ -47,7 +47,7 @@ public class KenjiProtocolDecoder extends BaseProtocolDecoder {
.number("G(d+)") // satellites
.any()
.compile();
-
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
diff --git a/src/org/traccar/protocol/KhdProtocol.java b/src/org/traccar/protocol/KhdProtocol.java
index a2edbfd5e..93edb0415 100644
--- a/src/org/traccar/protocol/KhdProtocol.java
+++ b/src/org/traccar/protocol/KhdProtocol.java
@@ -39,8 +39,8 @@ public class KhdProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(512, 3, 2));
- pipeline.addLast("objectDecoder", new KhdProtocolDecoder(KhdProtocol.this));
pipeline.addLast("objectEncoder", new KhdProtocolEncoder());
+ pipeline.addLast("objectDecoder", new KhdProtocolDecoder(KhdProtocol.this));
}
});
}
diff --git a/src/org/traccar/protocol/LaipacProtocol.java b/src/org/traccar/protocol/LaipacProtocol.java
index fff7b1c32..c2e5c585e 100644
--- a/src/org/traccar/protocol/LaipacProtocol.java
+++ b/src/org/traccar/protocol/LaipacProtocol.java
@@ -37,8 +37,8 @@ public class LaipacProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new LaipacProtocolDecoder(LaipacProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/ManPowerProtocol.java b/src/org/traccar/protocol/ManPowerProtocol.java
index 4fc194963..647a1bea7 100644
--- a/src/org/traccar/protocol/ManPowerProtocol.java
+++ b/src/org/traccar/protocol/ManPowerProtocol.java
@@ -37,8 +37,8 @@ public class ManPowerProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, ';'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new ManPowerProtocolDecoder(ManPowerProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/MegastekProtocol.java b/src/org/traccar/protocol/MegastekProtocol.java
index cdf891afe..f61a4443c 100644
--- a/src/org/traccar/protocol/MegastekProtocol.java
+++ b/src/org/traccar/protocol/MegastekProtocol.java
@@ -36,8 +36,8 @@ public class MegastekProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new MegastekFrameDecoder());
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new MegastekProtocolDecoder(MegastekProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/MeiligaoProtocol.java b/src/org/traccar/protocol/MeiligaoProtocol.java
index 05dd8834b..2e4226e19 100644
--- a/src/org/traccar/protocol/MeiligaoProtocol.java
+++ b/src/org/traccar/protocol/MeiligaoProtocol.java
@@ -43,15 +43,15 @@ public class MeiligaoProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new MeiligaoFrameDecoder());
- pipeline.addLast("objectDecoder", new MeiligaoProtocolDecoder(MeiligaoProtocol.this));
pipeline.addLast("objectEncoder", new MeiligaoProtocolEncoder());
+ pipeline.addLast("objectDecoder", new MeiligaoProtocolDecoder(MeiligaoProtocol.this));
}
});
serverList.add(new TrackerServer(new ConnectionlessBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("objectDecoder", new MeiligaoProtocolDecoder(MeiligaoProtocol.this));
pipeline.addLast("objectEncoder", new MeiligaoProtocolEncoder());
+ pipeline.addLast("objectDecoder", new MeiligaoProtocolDecoder(MeiligaoProtocol.this));
}
});
}
diff --git a/src/org/traccar/protocol/MeiligaoProtocolDecoder.java b/src/org/traccar/protocol/MeiligaoProtocolDecoder.java
index cb2139a00..5c17aab61 100644
--- a/src/org/traccar/protocol/MeiligaoProtocolDecoder.java
+++ b/src/org/traccar/protocol/MeiligaoProtocolDecoder.java
@@ -54,23 +54,19 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
.number("|(xxxx)?") // state
.groupBegin()
.number("|(xxxx),(xxxx)") // adc
+ .number("(?:,(xxxx),(xxxx),(xxxx),(xxxx),(xxxx),(xxxx))?")
.groupBegin()
- .number(",(xxxx),(xxxx),(xxxx),(xxxx),(xxxx),(xxxx)")
- .groupEnd("?")
- .groupBegin()
- .text("|")
- .groupBegin()
- .number("(x{16})") // cell
+ .number("|x{16}") // cell
.number("|(xx)") // gsm
- .number("|(x{8})|") // odometer
- .number("(x{9})") // odometer
+ .number("|(x{8})") // odometer
+ .or()
+ .number("|(x{9})") // odometer
.groupBegin()
.number("|(x{5,})") // rfid
.groupEnd("?")
.groupEnd("?")
.groupEnd("?")
.groupEnd("?")
- .groupEnd("?")
.any()
.compile();
@@ -283,15 +279,14 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
}
}
- position.set(Event.KEY_CID, parser.next());
-
if (parser.hasNext()) {
position.set(Event.KEY_GSM, parser.nextInt(16));
}
if (parser.hasNext()) {
position.set(Event.KEY_ODOMETER, parser.nextInt(16));
- } else if (parser.hasNext()) {
+ }
+ if (parser.hasNext()) {
position.set(Event.KEY_ODOMETER, parser.nextInt(16));
}
diff --git a/src/org/traccar/protocol/MeitrackProtocol.java b/src/org/traccar/protocol/MeitrackProtocol.java
index c957d4ea1..e5b5ddf2b 100644
--- a/src/org/traccar/protocol/MeitrackProtocol.java
+++ b/src/org/traccar/protocol/MeitrackProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,10 +31,12 @@ public class MeitrackProtocol extends BaseProtocol {
public MeitrackProtocol() {
super("meitrack");
setSupportedCommands(
+ Command.TYPE_POSITION_SINGLE,
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME,
Command.TYPE_ALARM_ARM,
- Command.TYPE_ALARM_DISARM);
+ Command.TYPE_ALARM_DISARM,
+ Command.TYPE_REQUEST_PHOTO);
}
@Override
@@ -44,6 +46,7 @@ public class MeitrackProtocol extends BaseProtocol {
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new MeitrackFrameDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("objectEncoder", new MeitrackProtocolEncoder());
pipeline.addLast("objectDecoder", new MeitrackProtocolDecoder(MeitrackProtocol.this));
}
};
@@ -53,6 +56,7 @@ public class MeitrackProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("objectEncoder", new MeitrackProtocolEncoder());
pipeline.addLast("objectDecoder", new MeitrackProtocolDecoder(MeitrackProtocol.this));
}
};
diff --git a/src/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/org/traccar/protocol/MeitrackProtocolDecoder.java
index e0ca01412..a920c6e76 100644
--- a/src/org/traccar/protocol/MeitrackProtocolDecoder.java
+++ b/src/org/traccar/protocol/MeitrackProtocolDecoder.java
@@ -24,6 +24,7 @@ import java.util.regex.Pattern;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
+import org.traccar.Context;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -237,10 +238,17 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
index = buf.indexOf(index + 1, buf.writerIndex(), (byte) ',');
String type = buf.toString(index + 1, 3, Charset.defaultCharset());
- if (type.equals("CCC")) {
- return decodeBinaryMessage(channel, remoteAddress, buf);
- } else {
- return decodeRegularMessage(channel, remoteAddress, buf);
+ switch (type) {
+ case "D03":
+ if (channel != null) {
+ String imei = Context.getIdentityManager().getDeviceById(getDeviceId()).getUniqueId();
+ channel.write("@@O46," + imei + ",D00,camera_picture.jpg,0*00\r\n");
+ }
+ return null;
+ case "CCC":
+ return decodeBinaryMessage(channel, remoteAddress, buf);
+ default:
+ return decodeRegularMessage(channel, remoteAddress, buf);
}
}
diff --git a/src/org/traccar/protocol/MeitrackProtocolEncoder.java b/src/org/traccar/protocol/MeitrackProtocolEncoder.java
index bfda2b7d2..381935c58 100644
--- a/src/org/traccar/protocol/MeitrackProtocolEncoder.java
+++ b/src/org/traccar/protocol/MeitrackProtocolEncoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,23 +16,36 @@
package org.traccar.protocol;
import org.traccar.StringProtocolEncoder;
+import org.traccar.helper.Checksum;
import org.traccar.helper.Log;
import org.traccar.model.Command;
public class MeitrackProtocolEncoder extends StringProtocolEncoder {
+ private Object formatCommand(Command command, char dataId, String content) {
+ String uniqueId = getUniqueId(command.getDeviceId());
+ int length = 1 + uniqueId.length() + 1 + content.length() + 5;
+ String result = String.format("@@%c%02d,%s,%s*", dataId, length, uniqueId, content);
+ result += Checksum.sum(result) + "\r\n";
+ return result;
+ }
+
@Override
protected Object encodeCommand(Command command) {
switch (command.getType()) {
+ case Command.TYPE_POSITION_SINGLE:
+ return formatCommand(command, 'Q', "A10");
case Command.TYPE_ENGINE_STOP:
- return formatCommand(command, "@@M33,{%s},C01,0,12222*18\r\n", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, 'M', "C01,0,12222");
case Command.TYPE_ENGINE_RESUME:
- return formatCommand(command, "@@M33,{%s},C01,0,02222*18\r\n", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, 'M', "C01,0,02222");
case Command.TYPE_ALARM_ARM:
- return formatCommand(command, "@@M33,{%s},C01,0,22122*18\r\n", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, 'M', "C01,0,22122");
case Command.TYPE_ALARM_DISARM:
- return formatCommand(command, "@@M33,{%s},C01,0,22022*18\r\n", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, 'M', "C01,0,22022");
+ case Command.TYPE_REQUEST_PHOTO:
+ return formatCommand(command, 'D', "D03,1,camera_picture.jpg");
default:
Log.warning(new UnsupportedOperationException(command.getType()));
break;
diff --git a/src/org/traccar/protocol/Mta6Protocol.java b/src/org/traccar/protocol/Mta6Protocol.java
index 8232b850c..607bf8118 100644
--- a/src/org/traccar/protocol/Mta6Protocol.java
+++ b/src/org/traccar/protocol/Mta6Protocol.java
@@ -35,8 +35,8 @@ public class Mta6Protocol extends BaseProtocol {
serverList.add(new TrackerServer(new ServerBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("httpDecoder", new HttpRequestDecoder());
pipeline.addLast("httpEncoder", new HttpResponseEncoder());
+ pipeline.addLast("httpDecoder", new HttpRequestDecoder());
pipeline.addLast("objectDecoder", new Mta6ProtocolDecoder(
Mta6Protocol.this, !Context.getConfig().getBoolean(getName() + ".can")));
}
diff --git a/src/org/traccar/protocol/MtxProtocol.java b/src/org/traccar/protocol/MtxProtocol.java
index 4fba981a5..e0bef8350 100644
--- a/src/org/traccar/protocol/MtxProtocol.java
+++ b/src/org/traccar/protocol/MtxProtocol.java
@@ -37,8 +37,8 @@ public class MtxProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new MtxProtocolDecoder(MtxProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/MxtProtocolDecoder.java b/src/org/traccar/protocol/MxtProtocolDecoder.java
index fedb7c715..53d5b8b09 100644
--- a/src/org/traccar/protocol/MxtProtocolDecoder.java
+++ b/src/org/traccar/protocol/MxtProtocolDecoder.java
@@ -114,7 +114,7 @@ public class MxtProtocolDecoder extends BaseProtocolDecoder {
}
if (BitUtil.check(infoGroups, 4)) {
- position.set("hours", buf.readUnsignedInt());
+ position.set(Event.KEY_HOURS, buf.readUnsignedInt());
}
if (BitUtil.check(infoGroups, 5)) {
diff --git a/src/org/traccar/protocol/OsmAndProtocol.java b/src/org/traccar/protocol/OsmAndProtocol.java
index 1e60ae807..3b473c435 100644
--- a/src/org/traccar/protocol/OsmAndProtocol.java
+++ b/src/org/traccar/protocol/OsmAndProtocol.java
@@ -35,8 +35,8 @@ public class OsmAndProtocol extends BaseProtocol {
serverList.add(new TrackerServer(new ServerBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("httpDecoder", new HttpRequestDecoder());
pipeline.addLast("httpEncoder", new HttpResponseEncoder());
+ pipeline.addLast("httpDecoder", new HttpRequestDecoder());
pipeline.addLast("objectDecoder", new OsmAndProtocolDecoder(OsmAndProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/PathAwayProtocol.java b/src/org/traccar/protocol/PathAwayProtocol.java
index dfa34abd5..d7efdfaf6 100644
--- a/src/org/traccar/protocol/PathAwayProtocol.java
+++ b/src/org/traccar/protocol/PathAwayProtocol.java
@@ -35,8 +35,8 @@ public class PathAwayProtocol extends BaseProtocol {
serverList.add(new TrackerServer(new ServerBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("httpDecoder", new HttpRequestDecoder());
pipeline.addLast("httpEncoder", new HttpResponseEncoder());
+ pipeline.addLast("httpDecoder", new HttpRequestDecoder());
pipeline.addLast("objectDecoder", new PathAwayProtocolDecoder(PathAwayProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/PiligrimProtocol.java b/src/org/traccar/protocol/PiligrimProtocol.java
index 0478835d9..11aafa412 100644
--- a/src/org/traccar/protocol/PiligrimProtocol.java
+++ b/src/org/traccar/protocol/PiligrimProtocol.java
@@ -36,9 +36,9 @@ public class PiligrimProtocol extends BaseProtocol {
serverList.add(new TrackerServer(new ServerBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("httpEncoder", new HttpResponseEncoder());
pipeline.addLast("httpDecoder", new HttpRequestDecoder());
pipeline.addLast("httpAggregator", new HttpChunkAggregator(16384));
- pipeline.addLast("httpEncoder", new HttpResponseEncoder());
pipeline.addLast("objectDecoder", new PiligrimProtocolDecoder(PiligrimProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/Pt3000Protocol.java b/src/org/traccar/protocol/Pt3000Protocol.java
index bde8e7709..3a22be214 100644
--- a/src/org/traccar/protocol/Pt3000Protocol.java
+++ b/src/org/traccar/protocol/Pt3000Protocol.java
@@ -37,8 +37,8 @@ public class Pt3000Protocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, 'd')); // probably wrong
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new Pt3000ProtocolDecoder(Pt3000Protocol.this));
}
});
diff --git a/src/org/traccar/protocol/SuntechProtocol.java b/src/org/traccar/protocol/SuntechProtocol.java
index d3f5d6009..e06ed2aac 100644
--- a/src/org/traccar/protocol/SuntechProtocol.java
+++ b/src/org/traccar/protocol/SuntechProtocol.java
@@ -41,10 +41,10 @@ public class SuntechProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, '\r'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
- pipeline.addLast("objectDecoder", new SuntechProtocolDecoder(SuntechProtocol.this));
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectEncoder", new SuntechProtocolEncoder());
+ pipeline.addLast("objectDecoder", new SuntechProtocolDecoder(SuntechProtocol.this));
}
});
}
diff --git a/src/org/traccar/protocol/T55Protocol.java b/src/org/traccar/protocol/T55Protocol.java
index 21f1d3e6c..041413a65 100644
--- a/src/org/traccar/protocol/T55Protocol.java
+++ b/src/org/traccar/protocol/T55Protocol.java
@@ -37,8 +37,8 @@ public class T55Protocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new T55ProtocolDecoder(T55Protocol.this));
}
});
diff --git a/src/org/traccar/protocol/T55ProtocolDecoder.java b/src/org/traccar/protocol/T55ProtocolDecoder.java
index 9c47d1ab0..71f493318 100644
--- a/src/org/traccar/protocol/T55ProtocolDecoder.java
+++ b/src/org/traccar/protocol/T55ProtocolDecoder.java
@@ -42,7 +42,13 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
.expression("([EW]),")
.number("(d+.?d*)?,") // speed
.number("(d+.?d*)?,") // course
- .number("(dd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd),") // date
+ .expression("[^*]+")
+ .text("*")
+ .expression("[^,]+")
+ .number(",(d+)") // satellites
+ .number(",(d+)") // imei
+ .number(",(d+)").optional(3)
.any()
.compile();
@@ -84,7 +90,7 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
private Position position = null;
- private Position decodeGprmc(String sentence, Channel channel) {
+ private Position decodeGprmc(String sentence, SocketAddress remoteAddress, Channel channel) {
if (channel != null) {
channel.write("OK1\r\n");
@@ -114,6 +120,14 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
position.setTime(dateBuilder.getDate());
+ if (parser.hasNext(3)) {
+ position.set(Event.KEY_SATELLITES, parser.next());
+ if (!identify(parser.next(), channel, remoteAddress)) {
+ return null;
+ }
+ position.setDeviceId(getDeviceId());
+ }
+
if (hasDeviceId()) {
return position;
} else {
@@ -217,7 +231,7 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
} else if (sentence.startsWith("IMEI")) {
identify(sentence.substring(5, sentence.length()), channel, remoteAddress);
} else if (sentence.startsWith("$GPFID")) {
- if (identify(sentence.substring(6, sentence.length()), channel, remoteAddress) && position != null) {
+ if (identify(sentence.substring(7, sentence.length()), channel, remoteAddress) && position != null) {
Position position = this.position;
position.setDeviceId(getDeviceId());
this.position = null;
@@ -226,7 +240,7 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
} else if (Character.isDigit(sentence.charAt(0)) && sentence.length() == 15) {
identify(sentence, channel, remoteAddress);
} else if (sentence.startsWith("$GPRMC")) {
- return decodeGprmc(sentence, channel);
+ return decodeGprmc(sentence, remoteAddress, channel);
} else if (sentence.startsWith("$GPGGA") && hasDeviceId()) {
return decodeGpgga(sentence);
} else if (sentence.startsWith("$GPRMA") && hasDeviceId()) {
diff --git a/src/org/traccar/protocol/TaipProtocol.java b/src/org/traccar/protocol/TaipProtocol.java
index 439fe7696..a3b744e70 100644
--- a/src/org/traccar/protocol/TaipProtocol.java
+++ b/src/org/traccar/protocol/TaipProtocol.java
@@ -38,14 +38,15 @@ public class TaipProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, '<'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new TaipProtocolDecoder(TaipProtocol.this, true));
}
});
serverList.add(new TrackerServer(new ConnectionlessBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("stringEncoder", new StringEncoder());
pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new TaipProtocolDecoder(TaipProtocol.this, false));
}
diff --git a/src/org/traccar/protocol/TelicFrameDecoder.java b/src/org/traccar/protocol/TelicFrameDecoder.java
new file mode 100644
index 000000000..2a6e121cf
--- /dev/null
+++ b/src/org/traccar/protocol/TelicFrameDecoder.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * 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.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.frame.FrameDecoder;
+
+public class TelicFrameDecoder extends FrameDecoder {
+
+ @Override
+ protected Object decode(
+ ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception {
+
+ if (buf.readableBytes() < 4) {
+ return null;
+ }
+
+ long length = buf.getUnsignedInt(buf.readerIndex());
+
+ if (length < 1024) {
+ if (buf.readableBytes() >= length + 4) {
+ buf.readUnsignedInt();
+ return buf.readBytes((int) length);
+ }
+ } else {
+ int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0);
+ if (endIndex >= 0) {
+ ChannelBuffer frame = buf.readBytes(endIndex - buf.readerIndex());
+ buf.readByte();
+ if (frame.readableBytes() > 0) {
+ return frame;
+ }
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/protocol/TelicProtocol.java b/src/org/traccar/protocol/TelicProtocol.java
new file mode 100644
index 000000000..464892431
--- /dev/null
+++ b/src/org/traccar/protocol/TelicProtocol.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * 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.string.StringDecoder;
+import org.traccar.BaseProtocol;
+import org.traccar.TrackerServer;
+
+import java.nio.ByteOrder;
+import java.util.List;
+
+public class TelicProtocol extends BaseProtocol {
+
+ public TelicProtocol() {
+ super("telic");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ TrackerServer server = new TrackerServer(new ServerBootstrap(), this.getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new TelicFrameDecoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
+ pipeline.addLast("objectDecoder", new TelicProtocolDecoder(TelicProtocol.this));
+ }
+ };
+ server.setEndianness(ByteOrder.LITTLE_ENDIAN);
+ serverList.add(server);
+ }
+
+}
diff --git a/src/org/traccar/protocol/TelikProtocolDecoder.java b/src/org/traccar/protocol/TelicProtocolDecoder.java
index 4171750d6..ba6d9c47e 100644
--- a/src/org/traccar/protocol/TelikProtocolDecoder.java
+++ b/src/org/traccar/protocol/TelicProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 - 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2014 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,9 +25,9 @@ import org.traccar.helper.PatternBuilder;
import org.traccar.model.Event;
import org.traccar.model.Position;
-public class TelikProtocolDecoder extends BaseProtocolDecoder {
+public class TelicProtocolDecoder extends BaseProtocolDecoder {
- public TelikProtocolDecoder(TelikProtocol protocol) {
+ public TelicProtocolDecoder(TelicProtocol protocol) {
super(protocol);
}
@@ -39,12 +39,19 @@ public class TelikProtocolDecoder extends BaseProtocolDecoder {
.number("d+,")
.number("(dd)(dd)(dd)") // date
.number("(dd)(dd)(dd),") // time
+ .groupBegin()
+ .number("(ddd)(dd)(dddd),") // longitude
+ .number("(dd)(dd)(dddd),") // latitude
+ .or()
.number("(-?d+),") // longitude
.number("(-?d+),") // latitude
+ .groupEnd()
.number("(d),") // validity
.number("(d+),") // speed
.number("(d+),") // course
.number("(d+),") // satellites
+ .expression("(?:[^,]*,){7}")
+ .number("(d+),")
.any()
.compile();
@@ -72,13 +79,22 @@ public class TelikProtocolDecoder extends BaseProtocolDecoder {
.setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
position.setTime(dateBuilder.getDate());
- position.setLongitude(parser.nextDouble() / 10000);
- position.setLatitude(parser.nextDouble() / 10000);
+ if (parser.hasNext(6)) {
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN));
+ }
+
+ if (parser.hasNext(2)) {
+ position.setLongitude(parser.nextDouble() / 10000);
+ position.setLatitude(parser.nextDouble() / 10000);
+ }
+
position.setValid(parser.nextInt() != 1);
position.setSpeed(parser.nextDouble());
position.setCourse(parser.nextDouble());
position.set(Event.KEY_SATELLITES, parser.next());
+ position.set(Event.KEY_BATTERY, parser.nextInt());
return position;
}
diff --git a/src/org/traccar/protocol/TeltonikaProtocol.java b/src/org/traccar/protocol/TeltonikaProtocol.java
index 859b2a08c..f944c3003 100644
--- a/src/org/traccar/protocol/TeltonikaProtocol.java
+++ b/src/org/traccar/protocol/TeltonikaProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* 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.traccar.BaseProtocol;
@@ -37,6 +38,12 @@ public class TeltonikaProtocol extends BaseProtocol {
pipeline.addLast("objectDecoder", new TeltonikaProtocolDecoder(TeltonikaProtocol.this));
}
});
+ serverList.add(new TrackerServer(new ConnectionlessBootstrap(), this.getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("objectDecoder", new TeltonikaProtocolDecoder(TeltonikaProtocol.this));
+ }
+ });
}
}
diff --git a/src/org/traccar/protocol/Tk102Protocol.java b/src/org/traccar/protocol/Tk102Protocol.java
index 4e1d067f9..1f4eda730 100644
--- a/src/org/traccar/protocol/Tk102Protocol.java
+++ b/src/org/traccar/protocol/Tk102Protocol.java
@@ -37,8 +37,8 @@ public class Tk102Protocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, ']'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new Tk102ProtocolDecoder(Tk102Protocol.this));
}
});
diff --git a/src/org/traccar/protocol/Tk103Protocol.java b/src/org/traccar/protocol/Tk103Protocol.java
index b14264091..324c01a31 100644
--- a/src/org/traccar/protocol/Tk103Protocol.java
+++ b/src/org/traccar/protocol/Tk103Protocol.java
@@ -38,16 +38,16 @@ public class Tk103Protocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, ')'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new Tk103ProtocolDecoder(Tk103Protocol.this));
}
});
serverList.add(new TrackerServer(new ConnectionlessBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new Tk103ProtocolDecoder(Tk103Protocol.this));
}
});
diff --git a/src/org/traccar/protocol/Tlt2hProtocol.java b/src/org/traccar/protocol/Tlt2hProtocol.java
index 3a1bf99ff..14787537d 100644
--- a/src/org/traccar/protocol/Tlt2hProtocol.java
+++ b/src/org/traccar/protocol/Tlt2hProtocol.java
@@ -37,8 +37,8 @@ public class Tlt2hProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(32 * 1024, "##\r\n"));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new Tlt2hProtocolDecoder(Tlt2hProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/TotemProtocol.java b/src/org/traccar/protocol/TotemProtocol.java
index 097f6a593..4d7f0a135 100644
--- a/src/org/traccar/protocol/TotemProtocol.java
+++ b/src/org/traccar/protocol/TotemProtocol.java
@@ -41,10 +41,10 @@ public class TotemProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new TotemFrameDecoder());
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
- pipeline.addLast("objectDecoder", new TotemProtocolDecoder(TotemProtocol.this));
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectEncoder", new TotemProtocolEncoder());
+ pipeline.addLast("objectDecoder", new TotemProtocolDecoder(TotemProtocol.this));
}
});
}
diff --git a/src/org/traccar/protocol/Tr20Protocol.java b/src/org/traccar/protocol/Tr20Protocol.java
index 8c5a27ae2..4e55d5f98 100644
--- a/src/org/traccar/protocol/Tr20Protocol.java
+++ b/src/org/traccar/protocol/Tr20Protocol.java
@@ -37,8 +37,8 @@ public class Tr20Protocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new Tr20ProtocolDecoder(Tr20Protocol.this));
}
});
diff --git a/src/org/traccar/protocol/Tr900Protocol.java b/src/org/traccar/protocol/Tr900Protocol.java
index 4db0a2239..d54e4cb3c 100644
--- a/src/org/traccar/protocol/Tr900Protocol.java
+++ b/src/org/traccar/protocol/Tr900Protocol.java
@@ -38,16 +38,16 @@ public class Tr900Protocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new Tr900ProtocolDecoder(Tr900Protocol.this));
}
});
serverList.add(new TrackerServer(new ConnectionlessBootstrap(), getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new Tr900ProtocolDecoder(Tr900Protocol.this));
}
});
diff --git a/src/org/traccar/protocol/TrackboxProtocol.java b/src/org/traccar/protocol/TrackboxProtocol.java
index 68554394e..5477de852 100644
--- a/src/org/traccar/protocol/TrackboxProtocol.java
+++ b/src/org/traccar/protocol/TrackboxProtocol.java
@@ -37,8 +37,8 @@ public class TrackboxProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new TrackboxProtocolDecoder(TrackboxProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/TrvProtocol.java b/src/org/traccar/protocol/TrvProtocol.java
index 916b7d612..af598ea02 100644
--- a/src/org/traccar/protocol/TrvProtocol.java
+++ b/src/org/traccar/protocol/TrvProtocol.java
@@ -37,8 +37,8 @@ public class TrvProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, '#'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new TrvProtocolDecoder(TrvProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/TrvProtocolDecoder.java b/src/org/traccar/protocol/TrvProtocolDecoder.java
index 94796fa5e..8075515c2 100644
--- a/src/org/traccar/protocol/TrvProtocolDecoder.java
+++ b/src/org/traccar/protocol/TrvProtocolDecoder.java
@@ -105,7 +105,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder {
position.set(Event.KEY_GSM, parser.nextInt());
position.set(Event.KEY_SATELLITES, parser.nextInt());
- position.set(Event.KEY_BATTERY , parser.nextInt());
+ position.set(Event.KEY_BATTERY, parser.nextInt());
position.set(Event.KEY_IGNITION, parser.nextInt() != 0);
position.set("arm", parser.nextInt());
diff --git a/src/org/traccar/protocol/TelikProtocol.java b/src/org/traccar/protocol/Tt8850Protocol.java
index b6b5ba14d..a409205c7 100644
--- a/src/org/traccar/protocol/TelikProtocol.java
+++ b/src/org/traccar/protocol/Tt8850Protocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,10 +24,10 @@ import org.traccar.TrackerServer;
import java.util.List;
-public class TelikProtocol extends BaseProtocol {
+public class Tt8850Protocol extends BaseProtocol {
- public TelikProtocol() {
- super("telik");
+ public Tt8850Protocol() {
+ super("tt8850");
}
@Override
@@ -35,9 +35,9 @@ public class TelikProtocol extends BaseProtocol {
serverList.add(new TrackerServer(new ServerBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, '\0'));
+ pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, "$"));
pipeline.addLast("stringDecoder", new StringDecoder());
- pipeline.addLast("objectDecoder", new TelikProtocolDecoder(TelikProtocol.this));
+ pipeline.addLast("objectDecoder", new Tt8850ProtocolDecoder(Tt8850Protocol.this));
}
});
}
diff --git a/src/org/traccar/protocol/Tt8850ProtocolDecoder.java b/src/org/traccar/protocol/Tt8850ProtocolDecoder.java
new file mode 100644
index 000000000..9979fd61d
--- /dev/null
+++ b/src/org/traccar/protocol/Tt8850ProtocolDecoder.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.helper.DateBuilder;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+public class Tt8850ProtocolDecoder extends BaseProtocolDecoder {
+
+ public Tt8850ProtocolDecoder(Tt8850Protocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .binary("0004,")
+ .number("xxxx,")
+ .expression("[01],")
+ .expression("GT...,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .expression("([^,]+),") // imei
+ .any()
+ .number("(d{1,2})?,") // gps accuracy
+ .number("(d{1,3}.d)?,") // speed
+ .number("(d{1,3})?,") // course
+ .number("(-?d{1,5}.d)?,") // altitude
+ .number("(-?d{1,3}.d{6}),") // longitude
+ .number("(-?d{1,2}.d{6}),") // latitude
+ .number("(dddd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd),") // time
+ .number("(0ddd)?,") // mcc
+ .number("(0ddd)?,") // mnc
+ .number("(xxxx)?,") // lac
+ .number("(xxxx)?,") // cell
+ .any()
+ .number("(dddd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd),") // time
+ .number("(xxxx)")
+ .compile();
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ Parser parser = new Parser(PATTERN, (String) msg);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+
+ if (!identify(parser.next(), channel, remoteAddress)) {
+ return null;
+ }
+ position.setDeviceId(getDeviceId());
+
+ position.setValid(parser.nextInt() < 20);
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
+ position.setAltitude(parser.nextDouble());
+ position.setLongitude(parser.nextDouble());
+ position.setLatitude(parser.nextDouble());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+
+ if (parser.hasNext(4)) {
+ position.set(Event.KEY_MCC, parser.nextInt());
+ position.set(Event.KEY_MNC, parser.nextInt());
+ position.set(Event.KEY_LAC, parser.nextInt(16));
+ position.set(Event.KEY_CID, parser.nextInt(16));
+ }
+
+ return position;
+ }
+
+}
diff --git a/src/org/traccar/protocol/UlbotechProtocolDecoder.java b/src/org/traccar/protocol/UlbotechProtocolDecoder.java
index bf0a9cc76..a5c608dd3 100644
--- a/src/org/traccar/protocol/UlbotechProtocolDecoder.java
+++ b/src/org/traccar/protocol/UlbotechProtocolDecoder.java
@@ -60,8 +60,8 @@ public class UlbotechProtocolDecoder extends BaseProtocolDecoder {
while (buf.readerIndex() < end) {
int parameterLength = buf.getUnsignedByte(buf.readerIndex()) >> 4;
- position.add(ObdDecoder.decode(buf.readUnsignedByte() & 0x0F, buf.readUnsignedByte(),
- ChannelBuffers.hexDump(buf.readBytes(parameterLength - 2))));
+ int mode = buf.readUnsignedByte() & 0x0F;
+ position.add(ObdDecoder.decode(mode, ChannelBuffers.hexDump(buf.readBytes(parameterLength - 1))));
}
}
diff --git a/src/org/traccar/protocol/WatchProtocol.java b/src/org/traccar/protocol/WatchProtocol.java
index 3a10f9c59..1198f689e 100644
--- a/src/org/traccar/protocol/WatchProtocol.java
+++ b/src/org/traccar/protocol/WatchProtocol.java
@@ -37,8 +37,8 @@ public class WatchProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, ']'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new WatchProtocolDecoder(WatchProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/WialonProtocol.java b/src/org/traccar/protocol/WialonProtocol.java
index 6fe924c2d..d0d3aa446 100644
--- a/src/org/traccar/protocol/WialonProtocol.java
+++ b/src/org/traccar/protocol/WialonProtocol.java
@@ -37,8 +37,8 @@ public class WialonProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(4 * 1024));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new WialonProtocolDecoder(WialonProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/XexunProtocolDecoder.java b/src/org/traccar/protocol/XexunProtocolDecoder.java
index 0929ee99b..4d4831a20 100644
--- a/src/org/traccar/protocol/XexunProtocolDecoder.java
+++ b/src/org/traccar/protocol/XexunProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2012 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,8 +38,8 @@ public class XexunProtocolDecoder extends BaseProtocolDecoder {
.expression("G[PN]RMC,")
.number("(dd)(dd)(dd).(d+),") // time
.expression("([AV]),") // validity
- .number("(d+)(dd.d+),([NS]),") // latitude
- .number("(d+)(dd.d+),([EW])?,") // longitude
+ .number("(d*?)(d?d.d+),([NS]),") // latitude
+ .number("(d*?)(d?d.d+),([EW])?,") // longitude
.number("(d+.?d*),") // speed
.number("(d+.?d*)?,") // course
.number("(dd)(dd)(dd),") // date
diff --git a/src/org/traccar/protocol/XirgoProtocol.java b/src/org/traccar/protocol/XirgoProtocol.java
index 83c373175..f186c731f 100644
--- a/src/org/traccar/protocol/XirgoProtocol.java
+++ b/src/org/traccar/protocol/XirgoProtocol.java
@@ -37,8 +37,8 @@ public class XirgoProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, "##"));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new XirgoProtocolDecoder(XirgoProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/YwtProtocol.java b/src/org/traccar/protocol/YwtProtocol.java
index e9cdb1615..3fa154ec0 100644
--- a/src/org/traccar/protocol/YwtProtocol.java
+++ b/src/org/traccar/protocol/YwtProtocol.java
@@ -37,8 +37,8 @@ public class YwtProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new YwtProtocolDecoder(YwtProtocol.this));
}
});
diff --git a/src/org/traccar/web/AsyncServlet.java b/src/org/traccar/web/AsyncServlet.java
index b10df5408..e4cb64c57 100644
--- a/src/org/traccar/web/AsyncServlet.java
+++ b/src/org/traccar/web/AsyncServlet.java
@@ -226,7 +226,7 @@ public class AsyncServlet extends BaseServlet {
synchronized (ASYNC_SESSIONS) {
if (Boolean.parseBoolean(req.getParameter("first")) || !ASYNC_SESSIONS.containsKey(userId)) {
- Collection<Long> devices = Context.getPermissionsManager().allowedDevices(userId);
+ Collection<Long> devices = Context.getPermissionsManager().getDevicePermissions(userId);
ASYNC_SESSIONS.put(userId, new AsyncSession(userId, devices));
}
diff --git a/src/org/traccar/web/BaseServlet.java b/src/org/traccar/web/BaseServlet.java
index 8b022d556..17f4f19cd 100644
--- a/src/org/traccar/web/BaseServlet.java
+++ b/src/org/traccar/web/BaseServlet.java
@@ -53,7 +53,7 @@ public abstract class BaseServlet extends HttpServlet {
String origin = req.getHeader(HttpHeaders.Names.ORIGIN);
String allowed = Context.getConfig().getString("web.origin");
- if (allowed == null) {
+ if (allowed == null || origin == null) {
resp.setHeader(HttpHeaders.Names.ACCESS_CONTROL_ALLOW_ORIGIN, ALLOW_ORIGIN_VALUE);
} else if (allowed.contains(origin)) {
String originSafe = URLEncoder.encode(origin, StandardCharsets.UTF_8.name());
diff --git a/src/org/traccar/web/WebServer.java b/src/org/traccar/web/WebServer.java
index d6cd19d87..4e764d5d6 100644
--- a/src/org/traccar/web/WebServer.java
+++ b/src/org/traccar/web/WebServer.java
@@ -42,7 +42,9 @@ import org.traccar.api.ResourceErrorHandler;
import org.traccar.api.SecurityRequestFilter;
import org.traccar.api.resource.CommandResource;
import org.traccar.api.resource.DeviceResource;
-import org.traccar.api.resource.PermissionResource;
+import org.traccar.api.resource.DevicePermissionResource;
+import org.traccar.api.resource.GroupPermissionResource;
+import org.traccar.api.resource.GroupResource;
import org.traccar.api.resource.PositionResource;
import org.traccar.api.resource.ServerResource;
import org.traccar.api.resource.SessionResource;
@@ -140,7 +142,8 @@ public class WebServer {
resourceConfig.register(SecurityRequestFilter.class);
resourceConfig.register(CorsResponseFilter.class);
resourceConfig.registerClasses(ServerResource.class, SessionResource.class, CommandResource.class,
- PermissionResource.class, DeviceResource.class, UserResource.class, PositionResource.class);
+ GroupPermissionResource.class, DevicePermissionResource.class, UserResource.class,
+ GroupResource.class, DeviceResource.class, PositionResource.class);
servletHandler.addServlet(new ServletHolder(new ServletContainer(resourceConfig)), "/*");
handlers.addHandler(servletHandler);