aboutsummaryrefslogtreecommitdiff
path: root/src/org/traccar
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/traccar')
-rw-r--r--src/org/traccar/BasePipelineFactory.java4
-rw-r--r--src/org/traccar/BaseProtocolDecoder.java9
-rw-r--r--src/org/traccar/ExtendedObjectDecoder.java4
-rw-r--r--src/org/traccar/MainEventHandler.java14
-rw-r--r--src/org/traccar/RemoteAddressHandler.java3
-rw-r--r--src/org/traccar/ReverseGeocoderHandler.java2
-rw-r--r--src/org/traccar/WebDataHandler.java57
-rw-r--r--src/org/traccar/database/ConnectionManager.java17
-rw-r--r--src/org/traccar/database/DataManager.java8
-rw-r--r--src/org/traccar/database/QueryBuilder.java170
-rw-r--r--src/org/traccar/helper/DateBuilder.java18
-rw-r--r--src/org/traccar/helper/Log.java4
-rw-r--r--src/org/traccar/helper/ObdDecoder.java78
-rw-r--r--src/org/traccar/helper/Parser.java13
-rw-r--r--src/org/traccar/helper/PatternBuilder.java2
-rw-r--r--src/org/traccar/model/Command.java1
-rw-r--r--src/org/traccar/model/Device.java4
-rw-r--r--src/org/traccar/model/Event.java1
-rw-r--r--src/org/traccar/model/Extensible.java6
-rw-r--r--src/org/traccar/protocol/ApelProtocolDecoder.java43
-rw-r--r--src/org/traccar/protocol/Ardi01ProtocolDecoder.java85
-rw-r--r--src/org/traccar/protocol/AtrackProtocolDecoder.java189
-rw-r--r--src/org/traccar/protocol/AutoFon45ProtocolDecoder.java79
-rw-r--r--src/org/traccar/protocol/AutoFonProtocolDecoder.java27
-rw-r--r--src/org/traccar/protocol/Avl301ProtocolDecoder.java38
-rw-r--r--src/org/traccar/protocol/BceProtocolDecoder.java3
-rw-r--r--src/org/traccar/protocol/BlackKiteProtocolDecoder.java3
-rw-r--r--src/org/traccar/protocol/CalAmpProtocolDecoder.java56
-rw-r--r--src/org/traccar/protocol/CarTrackProtocolDecoder.java128
-rw-r--r--src/org/traccar/protocol/CastelProtocolDecoder.java237
-rw-r--r--src/org/traccar/protocol/CellocatorProtocolDecoder.java27
-rw-r--r--src/org/traccar/protocol/CityeasyProtocolDecoder.java105
-rw-r--r--src/org/traccar/protocol/EasyTrackProtocolDecoder.java137
-rw-r--r--src/org/traccar/protocol/EelinkProtocolDecoder.java9
-rw-r--r--src/org/traccar/protocol/EnforaProtocolDecoder.java132
-rw-r--r--src/org/traccar/protocol/Ev603ProtocolDecoder.java103
-rw-r--r--src/org/traccar/protocol/FlextrackProtocolDecoder.java151
-rw-r--r--src/org/traccar/protocol/FreedomProtocolDecoder.java3
-rw-r--r--src/org/traccar/protocol/GalileoProtocolDecoder.java6
-rw-r--r--src/org/traccar/protocol/GatorProtocolDecoder.java38
-rw-r--r--src/org/traccar/protocol/Gl100ProtocolDecoder.java93
-rw-r--r--src/org/traccar/protocol/Gl200ProtocolDecoder.java13
-rw-r--r--src/org/traccar/protocol/GlobalSatProtocolDecoder.java4
-rw-r--r--src/org/traccar/protocol/GoSafeProtocolDecoder.java6
-rw-r--r--src/org/traccar/protocol/GotopProtocolDecoder.java87
-rw-r--r--src/org/traccar/protocol/Gps103Protocol.java3
-rw-r--r--src/org/traccar/protocol/Gps103ProtocolDecoder.java14
-rw-r--r--src/org/traccar/protocol/Gps103ProtocolEncoder.java2
-rw-r--r--src/org/traccar/protocol/GpsGateProtocolDecoder.java88
-rw-r--r--src/org/traccar/protocol/GpsMarkerProtocolDecoder.java119
-rw-r--r--src/org/traccar/protocol/GpsmtaProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/Gt02ProtocolDecoder.java45
-rw-r--r--src/org/traccar/protocol/H02ProtocolDecoder.java3
-rw-r--r--src/org/traccar/protocol/HaicomProtocolDecoder.java138
-rw-r--r--src/org/traccar/protocol/HuabaoFrameDecoder.java58
-rw-r--r--src/org/traccar/protocol/HuabaoProtocol.java42
-rw-r--r--src/org/traccar/protocol/HuabaoProtocolDecoder.java47
-rw-r--r--src/org/traccar/protocol/IntellitracProtocolDecoder.java147
-rw-r--r--src/org/traccar/protocol/Jt600ProtocolDecoder.java142
-rw-r--r--src/org/traccar/protocol/KhdProtocolDecoder.java38
-rw-r--r--src/org/traccar/protocol/M2mProtocolDecoder.java36
-rw-r--r--src/org/traccar/protocol/MaxonProtocolDecoder.java133
-rw-r--r--src/org/traccar/protocol/MegastekProtocolDecoder.java5
-rw-r--r--src/org/traccar/protocol/MeitrackProtocolDecoder.java215
-rw-r--r--src/org/traccar/protocol/MiniFinderProtocolDecoder.java99
-rw-r--r--src/org/traccar/protocol/Mta6ProtocolDecoder.java21
-rw-r--r--src/org/traccar/protocol/MxtProtocolDecoder.java20
-rw-r--r--src/org/traccar/protocol/NavigilProtocolDecoder.java3
-rw-r--r--src/org/traccar/protocol/NavisProtocolDecoder.java73
-rw-r--r--src/org/traccar/protocol/NoranProtocolDecoder.java31
-rw-r--r--src/org/traccar/protocol/OrionProtocolDecoder.java30
-rw-r--r--src/org/traccar/protocol/OsmAndProtocolDecoder.java10
-rw-r--r--src/org/traccar/protocol/PiligrimProtocolDecoder.java23
-rw-r--r--src/org/traccar/protocol/ProgressProtocolDecoder.java75
-rw-r--r--src/org/traccar/protocol/Pt3000ProtocolDecoder.java94
-rw-r--r--src/org/traccar/protocol/Pt502ProtocolDecoder.java143
-rw-r--r--src/org/traccar/protocol/RuptelaProtocolDecoder.java11
-rw-r--r--src/org/traccar/protocol/Stl060ProtocolDecoder.java67
-rw-r--r--src/org/traccar/protocol/SuntechProtocolDecoder.java100
-rw-r--r--src/org/traccar/protocol/T55ProtocolDecoder.java23
-rw-r--r--src/org/traccar/protocol/T800xProtocol.java43
-rw-r--r--src/org/traccar/protocol/T800xProtocolDecoder.java162
-rw-r--r--src/org/traccar/protocol/TaipProtocolDecoder.java123
-rw-r--r--src/org/traccar/protocol/TelikProtocolDecoder.java88
-rw-r--r--src/org/traccar/protocol/TeltonikaProtocolDecoder.java3
-rw-r--r--src/org/traccar/protocol/Tk102ProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/Tk103ProtocolDecoder.java44
-rw-r--r--src/org/traccar/protocol/Tr20ProtocolDecoder.java131
-rw-r--r--src/org/traccar/protocol/Tr900ProtocolDecoder.java114
-rw-r--r--src/org/traccar/protocol/TrackboxProtocolDecoder.java133
-rw-r--r--src/org/traccar/protocol/TramigoProtocolDecoder.java4
-rw-r--r--src/org/traccar/protocol/TrvProtocol.java (renamed from src/org/traccar/protocol/MaxonProtocol.java)12
-rw-r--r--src/org/traccar/protocol/TrvProtocolDecoder.java125
-rw-r--r--src/org/traccar/protocol/UlbotechProtocolDecoder.java13
-rw-r--r--src/org/traccar/protocol/VisiontekProtocolDecoder.java5
-rw-r--r--src/org/traccar/protocol/WatchProtocol.java (renamed from src/org/traccar/protocol/Ev603Protocol.java)12
-rw-r--r--src/org/traccar/protocol/WatchProtocolDecoder.java146
-rw-r--r--src/org/traccar/protocol/WondexProtocolDecoder.java109
-rw-r--r--src/org/traccar/web/AsyncServlet.java8
99 files changed, 2755 insertions, 2839 deletions
diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java
index 3b52287b8..c0952db86 100644
--- a/src/org/traccar/BasePipelineFactory.java
+++ b/src/org/traccar/BasePipelineFactory.java
@@ -40,11 +40,11 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
private DistanceHandler distanceHandler;
private ReverseGeocoderHandler reverseGeocoderHandler;
- private static class OpenChannelHandler extends SimpleChannelHandler {
+ private static final class OpenChannelHandler extends SimpleChannelHandler {
private final TrackerServer server;
- public OpenChannelHandler(TrackerServer server) {
+ private OpenChannelHandler(TrackerServer server) {
this.server = server;
}
diff --git a/src/org/traccar/BaseProtocolDecoder.java b/src/org/traccar/BaseProtocolDecoder.java
index e9c678930..f8abdcc85 100644
--- a/src/org/traccar/BaseProtocolDecoder.java
+++ b/src/org/traccar/BaseProtocolDecoder.java
@@ -46,7 +46,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
Device device = Context.getIdentityManager().getDeviceByUniqueId(uniqueId);
if (device != null) {
deviceId = device.getId();
- Context.getConnectionManager().setActiveDevice(deviceId, protocol, channel, remoteAddress);
+ Context.getConnectionManager().addActiveDevice(deviceId, protocol, channel, remoteAddress);
return true;
} else {
deviceId = 0;
@@ -95,4 +95,11 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
}
}
+ @Override
+ protected void onMessageEvent(Channel channel, SocketAddress remoteAddress, Object msg) {
+ if (hasDeviceId()) {
+ Context.getConnectionManager().updateDevice(deviceId, Device.STATUS_ONLINE, new Date());
+ }
+ }
+
}
diff --git a/src/org/traccar/ExtendedObjectDecoder.java b/src/org/traccar/ExtendedObjectDecoder.java
index 382ef869d..ca4561a3f 100644
--- a/src/org/traccar/ExtendedObjectDecoder.java
+++ b/src/org/traccar/ExtendedObjectDecoder.java
@@ -37,6 +37,7 @@ public abstract class ExtendedObjectDecoder implements ChannelUpstreamHandler {
MessageEvent e = (MessageEvent) evt;
Object originalMessage = e.getMessage();
Object decodedMessage = decode(e.getChannel(), e.getRemoteAddress(), originalMessage);
+ onMessageEvent(e.getChannel(), e.getRemoteAddress(), originalMessage); // call after decode
if (originalMessage == decodedMessage) {
ctx.sendUpstream(evt);
} else if (decodedMessage != null) {
@@ -50,6 +51,9 @@ public abstract class ExtendedObjectDecoder implements ChannelUpstreamHandler {
}
}
+ protected void onMessageEvent(Channel channel, SocketAddress remoteAddress, Object msg) {
+ }
+
protected abstract Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception;
}
diff --git a/src/org/traccar/MainEventHandler.java b/src/org/traccar/MainEventHandler.java
index 81376724b..37f0ee387 100644
--- a/src/org/traccar/MainEventHandler.java
+++ b/src/org/traccar/MainEventHandler.java
@@ -25,6 +25,7 @@ import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
import org.jboss.netty.handler.timeout.IdleStateEvent;
import org.traccar.helper.Log;
import org.traccar.model.Position;
+import java.text.SimpleDateFormat;
public class MainEventHandler extends IdleStateAwareChannelHandler {
@@ -39,14 +40,15 @@ public class MainEventHandler extends IdleStateAwareChannelHandler {
StringBuilder s = new StringBuilder();
s.append(formatChannel(e.getChannel())).append(" ");
s.append("id: ").append(position.getDeviceId()).append(", ");
- s.append("time: ").append(position.getFixTime()).append(", ");
- s.append("lat: ").append(position.getLatitude()).append(", ");
- s.append("lon: ").append(position.getLongitude()).append(", ");
- s.append("speed: ").append(position.getSpeed()).append(", ");
- s.append("course: ").append(position.getCourse());
+ s.append("time: ").append(
+ new SimpleDateFormat(Log.DATE_FORMAT).format(position.getFixTime())).append(", ");
+ s.append("lat: ").append(String.format("%.5f", position.getLatitude())).append(", ");
+ s.append("lon: ").append(String.format("%.5f", position.getLongitude())).append(", ");
+ s.append("speed: ").append(String.format("%.1f", position.getSpeed())).append(", ");
+ s.append("course: ").append(String.format("%.1f", position.getCourse()));
Log.info(s.toString());
- Context.getConnectionManager().update(position);
+ Context.getConnectionManager().updatePosition(position);
}
}
diff --git a/src/org/traccar/RemoteAddressHandler.java b/src/org/traccar/RemoteAddressHandler.java
index 45b441bb0..8bf2478a0 100644
--- a/src/org/traccar/RemoteAddressHandler.java
+++ b/src/org/traccar/RemoteAddressHandler.java
@@ -25,8 +25,7 @@ public class RemoteAddressHandler extends ExtendedObjectDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String hostAddress = ((InetSocketAddress) remoteAddress).getAddress().getHostAddress();
diff --git a/src/org/traccar/ReverseGeocoderHandler.java b/src/org/traccar/ReverseGeocoderHandler.java
index 62f045c17..8cbcc72b5 100644
--- a/src/org/traccar/ReverseGeocoderHandler.java
+++ b/src/org/traccar/ReverseGeocoderHandler.java
@@ -62,6 +62,8 @@ public class ReverseGeocoderHandler implements ChannelUpstreamHandler {
Channels.fireMessageReceived(ctx, position, e.getRemoteAddress());
}
});
+ } else {
+ Channels.fireMessageReceived(ctx, position, e.getRemoteAddress());
}
} else {
Channels.fireMessageReceived(ctx, message, e.getRemoteAddress());
diff --git a/src/org/traccar/WebDataHandler.java b/src/org/traccar/WebDataHandler.java
index c64ca8334..332fc5222 100644
--- a/src/org/traccar/WebDataHandler.java
+++ b/src/org/traccar/WebDataHandler.java
@@ -15,14 +15,18 @@
*/
package org.traccar;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Formatter;
import java.util.Locale;
import java.util.TimeZone;
import org.traccar.helper.Checksum;
+import org.traccar.helper.Log;
import org.traccar.model.Device;
import org.traccar.model.Event;
+import org.traccar.model.MiscFormatter;
import org.traccar.model.Position;
public class WebDataHandler extends BaseDataHandler {
@@ -46,8 +50,24 @@ public class WebDataHandler extends BaseDataHandler {
double lat = position.getLatitude();
double lon = position.getLongitude();
- f.format("%02d%07.4f,%c,", (int) Math.abs(lat), Math.abs(lat) % 1 * 60, lat < 0 ? 'S' : 'N');
- f.format("%03d%07.4f,%c,", (int) Math.abs(lon), Math.abs(lon) % 1 * 60, lon < 0 ? 'W' : 'E');
+
+ char hemisphere;
+
+ if (lat < 0) {
+ hemisphere = 'S';
+ } else {
+ hemisphere = 'N';
+ }
+
+ f.format("%02d%07.4f,%c,", (int) Math.abs(lat), Math.abs(lat) % 1 * 60, hemisphere);
+
+ if (lon < 0) {
+ hemisphere = 'W';
+ } else {
+ hemisphere = 'E';
+ }
+
+ f.format("%03d%07.4f,%c,", (int) Math.abs(lon), Math.abs(lon) % 1 * 60, hemisphere);
f.format("%.2f,%.2f,", position.getSpeed(), position.getCourse());
f.format("%1$td%1$tm%1$ty,,", calendar);
@@ -73,15 +93,42 @@ public class WebDataHandler extends BaseDataHandler {
Device device = Context.getIdentityManager().getDeviceById(position.getDeviceId());
+ String attributes = MiscFormatter.toJsonString(position.getAttributes());
+
String request = url
.replace("{uniqueId}", device.getUniqueId())
- .replace("{deviceId}", String.valueOf(device.getId()))
+ .replace("{deviceId}", String.valueOf(position.getDeviceId()))
+ .replace("{protocol}", String.valueOf(position.getProtocol()))
+ .replace("{deviceTime}", String.valueOf(position.getDeviceTime().getTime()))
.replace("{fixTime}", String.valueOf(position.getFixTime().getTime()))
- .replace("{latitude}", String.valueOf(position.getLatitude()))
+ .replace("{valid}", String.valueOf(position.getLatitude()))
+ .replace("{latitude}", String.valueOf(position.getValid()))
.replace("{longitude}", String.valueOf(position.getLongitude()))
- .replace("{gprmc}", formatSentence(position))
+ .replace("{altitude}", String.valueOf(position.getAltitude()))
+ .replace("{speed}", String.valueOf(position.getSpeed()))
+ .replace("{course}", String.valueOf(position.getCourse()))
.replace("{statusCode}", calculateStatus(position));
+ if (position.getAddress() != null) {
+ try {
+ request = request.replace("{address}", URLEncoder.encode(position.getAddress(), "UTF-8"));
+ } catch (UnsupportedEncodingException error) {
+ Log.warning(error);
+ }
+ }
+
+ if (request.contains("{attributes}")) {
+ try {
+ request = request.replace("{attributes}", URLEncoder.encode(attributes, "UTF-8"));
+ } catch (UnsupportedEncodingException error) {
+ Log.warning(error);
+ }
+ }
+
+ if (request.contains("{gprmc}")) {
+ request = request.replace("{gprmc}", formatSentence(position));
+ }
+
Context.getAsyncHttpClient().prepareGet(request).execute();
return position;
diff --git a/src/org/traccar/database/ConnectionManager.java b/src/org/traccar/database/ConnectionManager.java
index e45c83651..450f2f61f 100644
--- a/src/org/traccar/database/ConnectionManager.java
+++ b/src/org/traccar/database/ConnectionManager.java
@@ -18,6 +18,7 @@ package org.traccar.database;
import java.net.SocketAddress;
import java.sql.SQLException;
import java.util.Collection;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
@@ -27,6 +28,7 @@ import java.util.Set;
import org.jboss.netty.channel.Channel;
import org.traccar.Protocol;
import org.traccar.helper.Log;
+import org.traccar.model.Device;
import org.traccar.model.Position;
public class ConnectionManager {
@@ -47,13 +49,14 @@ public class ConnectionManager {
}
}
- public void setActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) {
+ public void addActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) {
activeDevices.put(deviceId, new ActiveDevice(deviceId, protocol, channel, remoteAddress));
}
public void removeActiveDevice(Channel channel) {
for (ActiveDevice activeDevice : activeDevices.values()) {
if (activeDevice.getChannel() == channel) {
+ updateDevice(activeDevice.getDeviceId(), Device.STATUS_OFFLINE, new Date());
activeDevices.remove(activeDevice.getDeviceId());
break;
}
@@ -64,12 +67,18 @@ public class ConnectionManager {
return activeDevices.get(deviceId);
}
- public synchronized void update(Position position) {
+ public synchronized void updateDevice(long deviceId, String status, Date time) {
+ // TODO update cache and call listener
+ /*Log.debug(deviceId + " " + status + " "
+ + new SimpleDateFormat(Log.DATE_FORMAT).format(time));*/
+ }
+
+ public synchronized void updatePosition(Position position) {
long deviceId = position.getDeviceId();
positions.put(deviceId, position);
if (listeners.containsKey(deviceId)) {
for (DataCacheListener listener : listeners.get(deviceId)) {
- listener.onUpdate(position);
+ listener.onUpdatePosition(position);
}
}
}
@@ -92,7 +101,7 @@ public class ConnectionManager {
}
public interface DataCacheListener {
- void onUpdate(Position position);
+ void onUpdatePosition(Position position);
}
public void addListener(Collection<Long> devices, DataCacheListener listener) {
diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java
index af2dd559a..24a07a05c 100644
--- a/src/org/traccar/database/DataManager.java
+++ b/src/org/traccar/database/DataManager.java
@@ -172,7 +172,7 @@ public class DataManager implements IdentityManager {
version = schema.getVersion();
}
- if (version != 301) {
+ if (version != 302) {
Log.error("Wrong database schema version (" + version + ")");
throw new RuntimeException();
}
@@ -241,7 +241,11 @@ public class DataManager implements IdentityManager {
User user = QueryBuilder.create(dataSource, getQuery("database.loginUser"))
.setString("email", email)
.executeQuerySingle(new User());
- return user != null && user.isPasswordValid(password) ? user : null;
+ if (user != null && user.isPasswordValid(password)) {
+ return user;
+ } else {
+ return null;
+ }
}
public Collection<User> getUsers() throws SQLException {
diff --git a/src/org/traccar/database/QueryBuilder.java b/src/org/traccar/database/QueryBuilder.java
index c3cde0723..ca6335556 100644
--- a/src/org/traccar/database/QueryBuilder.java
+++ b/src/org/traccar/database/QueryBuilder.java
@@ -281,6 +281,92 @@ public final class QueryBuilder {
}
}
+ private <T extends Factory> void addProcessors(
+ List<ResultSetProcessor<T>> processors, Class<?> parameterType, final Method method, final String name) {
+
+ if (parameterType.equals(boolean.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try {
+ method.invoke(object, resultSet.getBoolean(name));
+ } catch (IllegalAccessException | InvocationTargetException error) {
+ Log.warning(error);
+ }
+ }
+ });
+ } else if (parameterType.equals(int.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try {
+ method.invoke(object, resultSet.getInt(name));
+ } catch (IllegalAccessException | InvocationTargetException error) {
+ Log.warning(error);
+ }
+ }
+ });
+ } else if (parameterType.equals(long.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try {
+ method.invoke(object, resultSet.getLong(name));
+ } catch (IllegalAccessException | InvocationTargetException error) {
+ Log.warning(error);
+ }
+ }
+ });
+ } else if (parameterType.equals(double.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try {
+ method.invoke(object, resultSet.getDouble(name));
+ } catch (IllegalAccessException | InvocationTargetException error) {
+ Log.warning(error);
+ }
+ }
+ });
+ } else if (parameterType.equals(String.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try {
+ method.invoke(object, resultSet.getString(name));
+ } catch (IllegalAccessException | InvocationTargetException error) {
+ Log.warning(error);
+ }
+ }
+ });
+ } else if (parameterType.equals(Date.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try {
+ Timestamp timestamp = resultSet.getTimestamp(name);
+ if (timestamp != null) {
+ method.invoke(object, new Date(timestamp.getTime()));
+ }
+ } catch (IllegalAccessException | InvocationTargetException error) {
+ Log.warning(error);
+ }
+ }
+ });
+ } else if (parameterType.equals(Map.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try (JsonReader reader = Json.createReader(new StringReader(resultSet.getString(name)))) {
+ method.invoke(object, MiscFormatter.fromJson(reader.readObject()));
+ } catch (IllegalAccessException | InvocationTargetException | JsonParsingException error) {
+ Log.warning(error);
+ }
+ }
+ });
+ }
+ }
+
public <T extends Factory> Collection<T> executeQuery(T prototype) throws SQLException {
List<T> result = new LinkedList<>();
@@ -313,89 +399,7 @@ public final class QueryBuilder {
continue;
}
- Class<?> parameterType = method.getParameterTypes()[0];
-
- if (parameterType.equals(boolean.class)) {
- processors.add(new ResultSetProcessor<T>() {
- @Override
- public void process(T object, ResultSet resultSet) throws SQLException {
- try {
- method.invoke(object, resultSet.getBoolean(name));
- } catch (IllegalAccessException | InvocationTargetException error) {
- Log.warning(error);
- }
- }
- });
- } else if (parameterType.equals(int.class)) {
- processors.add(new ResultSetProcessor<T>() {
- @Override
- public void process(T object, ResultSet resultSet) throws SQLException {
- try {
- method.invoke(object, resultSet.getInt(name));
- } catch (IllegalAccessException | InvocationTargetException error) {
- Log.warning(error);
- }
- }
- });
- } else if (parameterType.equals(long.class)) {
- processors.add(new ResultSetProcessor<T>() {
- @Override
- public void process(T object, ResultSet resultSet) throws SQLException {
- try {
- method.invoke(object, resultSet.getLong(name));
- } catch (IllegalAccessException | InvocationTargetException error) {
- Log.warning(error);
- }
- }
- });
- } else if (parameterType.equals(double.class)) {
- processors.add(new ResultSetProcessor<T>() {
- @Override
- public void process(T object, ResultSet resultSet) throws SQLException {
- try {
- method.invoke(object, resultSet.getDouble(name));
- } catch (IllegalAccessException | InvocationTargetException error) {
- Log.warning(error);
- }
- }
- });
- } else if (parameterType.equals(String.class)) {
- processors.add(new ResultSetProcessor<T>() {
- @Override
- public void process(T object, ResultSet resultSet) throws SQLException {
- try {
- method.invoke(object, resultSet.getString(name));
- } catch (IllegalAccessException | InvocationTargetException error) {
- Log.warning(error);
- }
- }
- });
- } else if (parameterType.equals(Date.class)) {
- processors.add(new ResultSetProcessor<T>() {
- @Override
- public void process(T object, ResultSet resultSet) throws SQLException {
- try {
- Timestamp timestamp = resultSet.getTimestamp(name);
- if (timestamp != null) {
- method.invoke(object, new Date(timestamp.getTime()));
- }
- } catch (IllegalAccessException | InvocationTargetException error) {
- Log.warning(error);
- }
- }
- });
- } else if (parameterType.equals(Map.class)) {
- processors.add(new ResultSetProcessor<T>() {
- @Override
- public void process(T object, ResultSet resultSet) throws SQLException {
- try (JsonReader reader = Json.createReader(new StringReader(resultSet.getString(name)))) {
- method.invoke(object, MiscFormatter.fromJson(reader.readObject()));
- } catch (IllegalAccessException | InvocationTargetException | JsonParsingException error) {
- Log.warning(error);
- }
- }
- });
- }
+ addProcessors(processors, method.getParameterTypes()[0], method, name);
}
}
diff --git a/src/org/traccar/helper/DateBuilder.java b/src/org/traccar/helper/DateBuilder.java
index 77c6821aa..c52210326 100644
--- a/src/org/traccar/helper/DateBuilder.java
+++ b/src/org/traccar/helper/DateBuilder.java
@@ -25,13 +25,20 @@ public class DateBuilder {
public DateBuilder() {
this(TimeZone.getTimeZone("UTC"));
+ }
+ public DateBuilder(Date time) {
+ this(time, TimeZone.getTimeZone("UTC"));
}
public DateBuilder(TimeZone timeZone) {
+ this(new Date(0), timeZone);
+ }
+
+ public DateBuilder(Date time, TimeZone timeZone) {
calendar = Calendar.getInstance(timeZone);
calendar.clear();
- calendar.setTimeInMillis(0);
+ calendar.setTimeInMillis(time.getTime());
}
public DateBuilder setYear(int year) {
@@ -90,10 +97,19 @@ public class DateBuilder {
return this;
}
+ public DateBuilder addMillis(long millis) {
+ calendar.setTimeInMillis(calendar.getTimeInMillis() + millis);
+ return this;
+ }
+
public DateBuilder setTime(int hour, int minute, int second) {
return setHour(hour).setMinute(minute).setSecond(second);
}
+ public DateBuilder setTimeReverse(int second, int minute, int hour) {
+ return setHour(hour).setMinute(minute).setSecond(second);
+ }
+
public DateBuilder setTime(int hour, int minute, int second, int millis) {
return setHour(hour).setMinute(minute).setSecond(second).setMillis(millis);
}
diff --git a/src/org/traccar/helper/Log.java b/src/org/traccar/helper/Log.java
index 0e55a5445..2b747734e 100644
--- a/src/org/traccar/helper/Log.java
+++ b/src/org/traccar/helper/Log.java
@@ -40,6 +40,8 @@ public final class Log {
private Log() {
}
+ public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
+
private static final String LOGGER_NAME = "traccar";
private static final String STACK_PACKAGE = "org.traccar";
@@ -49,7 +51,7 @@ public final class Log {
public static void setupLogger(Config config) throws IOException {
- Layout layout = new PatternLayout("%d{yyyy-MM-dd HH:mm:ss} %5p: %m%n");
+ Layout layout = new PatternLayout("%d{" + DATE_FORMAT + "} %5p: %m%n");
Appender appender = new DailyRollingFileAppender(
layout, config.getString("logger.file"), "'.'yyyyMMdd");
diff --git a/src/org/traccar/helper/ObdDecoder.java b/src/org/traccar/helper/ObdDecoder.java
new file mode 100644
index 000000000..35fa4dc07
--- /dev/null
+++ b/src/org/traccar/helper/ObdDecoder.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2015 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.helper;
+
+import org.traccar.model.Event;
+
+import java.util.AbstractMap;
+import java.util.Map;
+
+public final class ObdDecoder {
+
+ private ObdDecoder() {
+ }
+
+ private static final int MODE_CURRENT = 0x01;
+ private static final int MODE_FREEZE_FRAME = 0x02;
+
+ private static final int PID_ENGINE_LOAD = 0x04;
+ private static final int PID_COOLANT_TEMPERATURE = 0x05;
+ private static final int PID_ENGINE_RPM = 0x0C;
+ private static final int PID_VEHICLE_SPEED = 0x0D;
+ private static final int PID_THROTTLE_POSITION = 0x11;
+ private static final int PID_MIL_DISTANCE = 0x21;
+ 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) {
+ switch (mode) {
+ case MODE_CURRENT:
+ case MODE_FREEZE_FRAME:
+ return decodeData(pid, value);
+ default:
+ return null;
+ }
+ }
+
+ private static Map.Entry<String, Object> createEntry(String key, Object value) {
+ return new AbstractMap.SimpleEntry<>(key, value);
+ }
+
+ private static Map.Entry<String, Object> decodeData(int pid, String value) {
+ int intValue = Integer.parseInt(value, 16);
+ switch (pid) {
+ case PID_ENGINE_LOAD:
+ return createEntry("engine-load", intValue * 100 / 255);
+ case PID_COOLANT_TEMPERATURE:
+ return createEntry("coolant-temperature", intValue - 40);
+ case PID_ENGINE_RPM:
+ return createEntry(Event.KEY_RPM, intValue / 4);
+ case PID_VEHICLE_SPEED:
+ return createEntry(Event.KEY_OBD_SPEED, intValue);
+ case PID_THROTTLE_POSITION:
+ return createEntry("throttle", intValue * 100 / 255);
+ case PID_MIL_DISTANCE:
+ return createEntry("mil-distance", intValue);
+ case PID_FUEL_LEVEL:
+ return createEntry(Event.KEY_FUEL, intValue * 100 / 255);
+ case PID_DISTANCE_CLEARED:
+ return createEntry(Event.KEY_FUEL, intValue);
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/src/org/traccar/helper/Parser.java b/src/org/traccar/helper/Parser.java
index bda7d6366..c5f5d2e37 100644
--- a/src/org/traccar/helper/Parser.java
+++ b/src/org/traccar/helper/Parser.java
@@ -87,9 +87,11 @@ public class Parser {
}
public enum CoordinateFormat {
+ DEG_DEG,
DEG_HEM,
DEG_MIN_HEM,
DEG_MIN_MIN_HEM,
+ HEM_DEG_MIN_MIN,
HEM_DEG,
HEM_DEG_MIN,
HEM_DEG_MIN_HEM
@@ -97,9 +99,12 @@ public class Parser {
public double nextCoordinate(CoordinateFormat format) {
double coordinate;
- String hemisphere;
+ String hemisphere = null;
switch (format) {
+ case DEG_DEG:
+ coordinate = Double.parseDouble(next() + '.' + next());
+ break;
case DEG_HEM:
coordinate = nextDouble();
hemisphere = next();
@@ -126,6 +131,12 @@ public class Parser {
hemisphere = next();
}
break;
+ case HEM_DEG_MIN_MIN:
+ hemisphere = next();
+ coordinate = nextInt();
+ coordinate += Double.parseDouble(next() + '.' + next()) / 60;
+ break;
+ case DEG_MIN_HEM:
default:
coordinate = nextInt();
coordinate += nextDouble() / 60;
diff --git a/src/org/traccar/helper/PatternBuilder.java b/src/org/traccar/helper/PatternBuilder.java
index 6742e7130..3a8bdd868 100644
--- a/src/org/traccar/helper/PatternBuilder.java
+++ b/src/org/traccar/helper/PatternBuilder.java
@@ -48,7 +48,7 @@ public class PatternBuilder {
s = s.replace("dddd", "d{4}").replace("ddd", "d{3}").replace("dd", "d{2}");
s = s.replace("xxxx", "x{4}").replace("xxx", "x{3}").replace("xx", "x{2}");
- s = s.replace("d", "\\d").replace("x", "\\p{XDigit}").replaceAll("([\\.])", "\\\\$1");
+ s = s.replace("d", "\\d").replace("x", "[0-9a-fA-F]").replaceAll("([\\.])", "\\\\$1");
s = s.replaceAll("\\|$", "\\\\|").replaceAll("^\\|", "\\\\|"); // special case for delimiter
fragments.add(s);
diff --git a/src/org/traccar/model/Command.java b/src/org/traccar/model/Command.java
index 99525a02b..abca811a2 100644
--- a/src/org/traccar/model/Command.java
+++ b/src/org/traccar/model/Command.java
@@ -25,6 +25,7 @@ public class Command extends Extensible implements Factory {
public static final String TYPE_ALARM_ARM = "alarmArm";
public static final String TYPE_ALARM_DISARM = "alarmDisarm";
public static final String TYPE_SET_TIMEZONE = "setTimezone";
+ public static final String TYPE_REQUEST_PHOTO = "requestPhoto";
public static final String KEY_UNIQUE_ID = "uniqueId";
public static final String KEY_FREQUENCY = "frequency";
diff --git a/src/org/traccar/model/Device.java b/src/org/traccar/model/Device.java
index 698505983..fd62cc691 100644
--- a/src/org/traccar/model/Device.java
+++ b/src/org/traccar/model/Device.java
@@ -54,6 +54,10 @@ public class Device implements Factory {
this.uniqueId = uniqueId;
}
+ public static final String STATUS_UNKNOWN = "unknown";
+ public static final String STATUS_ONLINE = "online";
+ public static final String STATUS_OFFLINE = "offline";
+
private String status;
public String getStatus() {
diff --git a/src/org/traccar/model/Event.java b/src/org/traccar/model/Event.java
index 172203a86..832e0e7c5 100644
--- a/src/org/traccar/model/Event.java
+++ b/src/org/traccar/model/Event.java
@@ -50,6 +50,7 @@ public abstract class Event extends Extensible {
public static final String KEY_DOOR = "door";
public static final String KEY_RPM = "rpm";
public static final String KEY_HOURS = "hours";
+ public static final String KEY_VIN = "vin";
public static final String KEY_OBD_SPEED = "obd-speed";
public static final String KEY_OBD_ODOMETER = "obd-odometer";
diff --git a/src/org/traccar/model/Extensible.java b/src/org/traccar/model/Extensible.java
index a821d0e43..40a286987 100644
--- a/src/org/traccar/model/Extensible.java
+++ b/src/org/traccar/model/Extensible.java
@@ -52,4 +52,10 @@ public abstract class Extensible extends Message {
}
}
+ public void add(Map.Entry<String, Object> entry) {
+ if (entry.getValue() != null) {
+ attributes.put(entry.getKey(), entry.getValue());
+ }
+ }
+
}
diff --git a/src/org/traccar/protocol/ApelProtocolDecoder.java b/src/org/traccar/protocol/ApelProtocolDecoder.java
index a04aa01af..e346e7d88 100644
--- a/src/org/traccar/protocol/ApelProtocolDecoder.java
+++ b/src/org/traccar/protocol/ApelProtocolDecoder.java
@@ -18,16 +18,14 @@ package org.traccar.protocol;
import java.net.SocketAddress;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
-import java.util.Calendar;
+import java.util.Date;
import java.util.LinkedList;
import java.util.List;
-import java.util.TimeZone;
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.Checksum;
-import org.traccar.helper.Log;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -90,8 +88,7 @@ public class ApelProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
int type = buf.readUnsignedShort();
@@ -104,8 +101,7 @@ public class ApelProtocolDecoder extends BaseProtocolDecoder {
}
if (type == MSG_TRACKER_ID) {
- Log.warning("Unsupported authentication type");
- return null;
+ return null; // unsupported authentication type
}
if (type == MSG_TRACKER_ID_EXT) {
@@ -139,7 +135,6 @@ public class ApelProtocolDecoder extends BaseProtocolDecoder {
position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
- // Message index
int subtype = type;
if (type == MSG_LOG_RECORDS) {
position.set(Event.KEY_ARCHIVE, true);
@@ -154,19 +149,10 @@ public class ApelProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedShort(); // length
}
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.setTimeInMillis(buf.readUnsignedInt() * 1000);
- position.setTime(time.getTime());
-
- // Latitude
+ position.setTime(new Date(buf.readUnsignedInt() * 1000));
position.setLatitude(buf.readInt() * 180.0 / 0x7FFFFFFF);
-
- // Longitude
position.setLongitude(buf.readInt() * 180.0 / 0x7FFFFFFF);
- // Speed and Validity
if (subtype == MSG_STATE_FULL_INFO_T104) {
int speed = buf.readUnsignedByte();
position.setValid(speed != 255);
@@ -175,39 +161,25 @@ public class ApelProtocolDecoder extends BaseProtocolDecoder {
} else {
int speed = buf.readShort();
position.setValid(speed != -1);
- position.setSpeed(UnitsConverter.knotsFromKph(speed / 100.0));
+ position.setSpeed(UnitsConverter.knotsFromKph(speed * 0.01));
}
- // Course
- position.setCourse(buf.readShort() / 100.0);
-
- // Altitude
+ position.setCourse(buf.readShort() * 0.01);
position.setAltitude(buf.readShort());
if (subtype == MSG_STATE_FULL_INFO_T104) {
- // Satellites
position.set(Event.KEY_SATELLITES, buf.readUnsignedByte());
-
- // Cell signal
position.set(Event.KEY_GSM, buf.readUnsignedByte());
-
- // Event type
position.set(Event.KEY_EVENT, buf.readUnsignedShort());
-
- // Odometer
position.set(Event.KEY_ODOMETER, buf.readUnsignedInt());
-
- // Input/Output
position.set(Event.KEY_INPUT, buf.readUnsignedByte());
position.set(Event.KEY_OUTPUT, buf.readUnsignedByte());
- // Analog sensors
for (int i = 1; i <= 8; i++) {
position.set(Event.PREFIX_ADC + i, buf.readUnsignedShort());
}
- // Counters
position.set(Event.PREFIX_COUNT + 1, buf.readUnsignedInt());
position.set(Event.PREFIX_COUNT + 2, buf.readUnsignedInt());
position.set(Event.PREFIX_COUNT + 3, buf.readUnsignedInt());
@@ -216,8 +188,7 @@ public class ApelProtocolDecoder extends BaseProtocolDecoder {
positions.add(position);
}
- // Skip CRC
- buf.readUnsignedInt();
+ buf.readUnsignedInt(); // crc
if (type == MSG_LOG_RECORDS) {
requestArchive(channel);
diff --git a/src/org/traccar/protocol/Ardi01ProtocolDecoder.java b/src/org/traccar/protocol/Ardi01ProtocolDecoder.java
index 738af9bb1..80186894a 100644
--- a/src/org/traccar/protocol/Ardi01ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Ardi01ProtocolDecoder.java
@@ -16,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
@@ -32,75 +32,56 @@ public class Ardi01ProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "(\\d+)," + // IMEI
- "(\\d{4})(\\d{2})(\\d{2})" + // Date (YYYYMMDD)
- "(\\d{2})(\\d{2})(\\d{2})," + // Time (HHMMSS)
- "(-?\\d+\\.\\d+)," + // Longitude
- "(-?\\d+\\.\\d+)," + // Latitude
- "(\\d+\\.?\\d*)," + // Speed
- "(\\d+\\.?\\d*)," + // Course
- "(-?\\d+\\.?\\d*)," + // Altitude
- "(\\d+)," + // Satellites
- "(\\d+)," + // Event
- "(\\d+)," + // Battery
- "(-?\\d+)"); // Temperature
+ private static final Pattern PATTERN = new PatternBuilder()
+ .number("(d+),") // imei
+ .number("(dddd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd),") // time
+ .number("(-?d+.d+),") // longitude
+ .number("(-?d+.d+),") // latitude
+ .number("(d+.?d*),") // speed
+ .number("(d+.?d*),") // course
+ .number("(-?d+.?d*),") // altitude
+ .number("(d+),") // satellites
+ .number("(d+),") // event
+ .number("(d+),") // battery
+ .number("(-?d+)") // temperature
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String sentence = (String) msg;
-
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
- // Detect device
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Date and time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Location data
- position.setLongitude(Double.parseDouble(parser.group(index++)));
- position.setLatitude(Double.parseDouble(parser.group(index++)));
- position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(parser.group(index++))));
- position.setCourse(Double.parseDouble(parser.group(index++)));
- position.setAltitude(Double.parseDouble(parser.group(index++)));
+ position.setLongitude(parser.nextDouble());
+ position.setLatitude(parser.nextDouble());
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
+ position.setAltitude(parser.nextDouble());
- // Satellites
- int satellites = Integer.parseInt(parser.group(index++));
+ int satellites = parser.nextInt();
position.setValid(satellites >= 3);
position.set(Event.KEY_SATELLITES, satellites);
- // Event
- position.set(Event.KEY_EVENT, parser.group(index++));
-
- // Input
- position.set(Event.KEY_BATTERY, parser.group(index++));
-
- // Output
- position.set(Event.PREFIX_TEMP + 1, parser.group(index++));
+ position.set(Event.KEY_EVENT, parser.next());
+ position.set(Event.KEY_BATTERY, parser.next());
+ position.set(Event.PREFIX_TEMP + 1, parser.next());
return position;
}
diff --git a/src/org/traccar/protocol/AtrackProtocolDecoder.java b/src/org/traccar/protocol/AtrackProtocolDecoder.java
index 792f22c07..e939cb88d 100644
--- a/src/org/traccar/protocol/AtrackProtocolDecoder.java
+++ b/src/org/traccar/protocol/AtrackProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2013 - 2015 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,17 +24,39 @@ import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
+import org.traccar.Context;
+import org.traccar.helper.DateBuilder;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Event;
import org.traccar.model.Position;
public class AtrackProtocolDecoder extends BaseProtocolDecoder {
+ private static final int MIN_DATA_LENGTH = 40;
+
+ private boolean longDate;
+ private boolean custom;
+ private String form;
+
public AtrackProtocolDecoder(AtrackProtocol protocol) {
super(protocol);
+
+ longDate = Context.getConfig().getBoolean(getProtocolName() + ".longDate");
+
+ custom = Context.getConfig().getBoolean(getProtocolName() + ".custom");
+ form = Context.getConfig().getString(getProtocolName() + ".form");
+ if (form != null) {
+ custom = true;
+ }
}
- private static final int MIN_DATA_LENGTH = 40;
+ public void setLongDate(boolean longDate) {
+ this.longDate = longDate;
+ }
+
+ public void setCustom(boolean custom) {
+ this.custom = custom;
+ }
private static void sendResponse(Channel channel, SocketAddress remoteAddress, long rawId, int index) {
if (channel != null) {
@@ -47,32 +69,115 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
}
private static String readString(ChannelBuffer buf) {
-
String result = null;
- int length = 0;
- while (buf.getByte(buf.readerIndex() + length) != 0) {
- length += 1;
- }
- if (length != 0) {
- result = buf.toString(buf.readerIndex(), length, Charset.defaultCharset());
- buf.skipBytes(length);
+ int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0);
+ if (index > buf.readerIndex()) {
+ result = buf.readBytes(index - buf.readerIndex()).toString(Charset.defaultCharset());
}
buf.readByte();
-
return result;
}
+ private void readCustomData(Position position, ChannelBuffer buf, String form) {
+ String[] keys = form.substring(1).split("%");
+ for (String key : keys) {
+ switch (key) {
+ case "SA":
+ position.set(Event.KEY_SATELLITES, buf.readUnsignedByte());
+ break;
+ case "MV":
+ position.set(Event.KEY_POWER, buf.readUnsignedShort());
+ break;
+ case "BV":
+ position.set(Event.KEY_BATTERY, buf.readUnsignedShort());
+ break;
+ case "GQ":
+ position.set(Event.KEY_GSM, buf.readUnsignedByte());
+ break;
+ case "CE":
+ position.set(Event.KEY_CELL, buf.readUnsignedInt());
+ break;
+ case "LC":
+ position.set(Event.KEY_LAC, buf.readUnsignedShort());
+ break;
+ case "CN":
+ buf.readUnsignedInt(); // mcc + mnc
+ break;
+ case "RL":
+ buf.readUnsignedByte(); // rxlev
+ break;
+ case "PC":
+ buf.readUnsignedInt(); // pulse count
+ break;
+ case "AT":
+ position.setAltitude(buf.readUnsignedInt());
+ break;
+ case "RP":
+ position.set(Event.KEY_RPM, buf.readUnsignedShort());
+ break;
+ case "GS":
+ buf.readUnsignedByte(); // gsm status
+ break;
+ case "DT":
+ position.set(Event.KEY_ARCHIVE, buf.readUnsignedByte() == 1);
+ break;
+ case "VN":
+ position.set(Event.KEY_VIN, readString(buf));
+ break;
+ case "MF":
+ buf.readUnsignedShort(); // mass air flow rate
+ break;
+ case "EL":
+ buf.readUnsignedByte(); // engine load
+ break;
+ case "TR":
+ buf.readUnsignedByte(); // throttle position
+ break;
+ case "ET":
+ buf.readUnsignedShort(); // engine coolant temp
+ break;
+ case "FL":
+ position.set(Event.KEY_FUEL, buf.readUnsignedByte());
+ break;
+ case "ML":
+ buf.readUnsignedByte(); // mil status
+ break;
+ case "FC":
+ buf.readUnsignedInt(); // fuel used
+ break;
+ case "CI":
+ readString(buf); // format string
+ break;
+ case "AV1":
+ position.set(Event.PREFIX_ADC + 1, buf.readUnsignedShort());
+ break;
+ case "NC":
+ readString(buf); // gsm neighbor cell info
+ break;
+ case "SM":
+ buf.readUnsignedShort(); // max speed between reports
+ break;
+ case "GL":
+ readString(buf); // google link
+ break;
+ case "MA":
+ readString(buf); // mac address
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
- // Keep alive message
if (buf.getUnsignedShort(buf.readerIndex()) == 0xfe02) {
if (channel != null) {
- channel.write(buf, remoteAddress);
+ channel.write(buf, remoteAddress); // keep-alive message
}
return null;
}
@@ -82,72 +187,70 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedShort(); // length
int index = buf.readUnsignedShort();
- // Get device id
long id = buf.readLong();
if (!identify(String.valueOf(id), channel, remoteAddress)) {
return null;
}
- // Send acknowledgement
sendResponse(channel, remoteAddress, id, index);
List<Position> positions = new LinkedList<>();
while (buf.readableBytes() >= MIN_DATA_LENGTH) {
- // Create new position
Position position = new Position();
- position.setDeviceId(getDeviceId());
position.setProtocol(getProtocolName());
+ position.setDeviceId(getDeviceId());
+
+ if (longDate) {
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(buf.readUnsignedShort(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ position.setTime(dateBuilder.getDate());
- // Date and time
- position.setTime(new Date(buf.readUnsignedInt() * 1000)); // gps time
- buf.readUnsignedInt(); // rtc time
- buf.readUnsignedInt(); // send time
+ buf.skipBytes(7 + 7);
+
+
+ } else {
+
+ position.setFixTime(new Date(buf.readUnsignedInt() * 1000));
+ position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000));
+ buf.readUnsignedInt(); // send time
+ }
- // Coordinates
position.setValid(true);
position.setLongitude(buf.readInt() * 0.000001);
position.setLatitude(buf.readInt() * 0.000001);
-
- // Course
position.setCourse(buf.readUnsignedShort());
- // Report type
position.set(Event.KEY_TYPE, buf.readUnsignedByte());
-
- // Odometer
position.set(Event.KEY_ODOMETER, buf.readUnsignedInt() * 0.1);
-
- // Accuracy
position.set(Event.KEY_HDOP, buf.readUnsignedShort() * 0.1);
-
- // Input
position.set(Event.KEY_INPUT, buf.readUnsignedByte());
- // Speed
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort()));
- // Output
position.set(Event.KEY_OUTPUT, buf.readUnsignedByte());
-
- // ADC
position.set(Event.PREFIX_ADC + 1, buf.readUnsignedShort() * 0.001);
- // Driver
position.set("driver", readString(buf));
- // Temperature
position.set(Event.PREFIX_TEMP + 1, buf.readShort() * 0.1);
position.set(Event.PREFIX_TEMP + 2, buf.readShort() * 0.1);
- // Text Message
position.set("message", readString(buf));
- // With AT$FORM Command you can extend atrack protocol.
- // For example adding AT$FORM %FC /Fuel used you can add the line in this position:
- // position.set("fuelused", buf.readUnsignedInt() * 0.1);
+ if (custom) {
+ String form = this.form;
+ if (form == null) {
+ form = readString(buf).substring("%CI".length());
+ }
+ readCustomData(position, buf, form);
+ }
+
positions.add(position);
+
}
return positions;
diff --git a/src/org/traccar/protocol/AutoFon45ProtocolDecoder.java b/src/org/traccar/protocol/AutoFon45ProtocolDecoder.java
index 92ffaedeb..8ff306c41 100644
--- a/src/org/traccar/protocol/AutoFon45ProtocolDecoder.java
+++ b/src/org/traccar/protocol/AutoFon45ProtocolDecoder.java
@@ -1,4 +1,5 @@
/*
+ * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
* Copyright 2015 Vitaly Litvak (vitavaque@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,12 +18,12 @@ package org.traccar.protocol;
import java.net.SocketAddress;
import java.util.Arrays;
-import java.util.Calendar;
-import java.util.TimeZone;
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.model.Event;
import org.traccar.model.Position;
import static org.traccar.protocol.AutoFon45FrameDecoder.MSG_LOCATION;
@@ -30,9 +31,17 @@ import static org.traccar.protocol.AutoFon45FrameDecoder.MSG_LOGIN;
public class AutoFon45ProtocolDecoder extends BaseProtocolDecoder {
- private static double convertCoordinate(short degrees, int raw) {
- double seconds = (raw >> 4 & 0xffffff) / 600000.0;
- return (degrees + seconds) * ((raw & 0x0f) == 0 ? -1 : 1);
+ public AutoFon45ProtocolDecoder(AutoFon45Protocol protocol) {
+ super(protocol);
+ }
+
+ private static double convertCoordinate(short degrees, int minutes) {
+ double value = degrees + BitUtil.from(minutes, 4) / 600000.0;
+ if (BitUtil.check(minutes, 0)) {
+ return value;
+ } else {
+ return -value;
+ }
}
private static byte checksum(byte[] bytes, int offset, int len) {
@@ -46,45 +55,43 @@ public class AutoFon45ProtocolDecoder extends BaseProtocolDecoder {
return result;
}
- public AutoFon45ProtocolDecoder(AutoFon45Protocol protocol) {
- super(protocol);
- }
-
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
- int type = buf.getUnsignedByte(0);
+ int type = buf.getUnsignedByte(buf.readerIndex());
if (type == MSG_LOGIN) {
+
byte[] bytes = new byte[19];
buf.readBytes(bytes);
- String imei = ChannelBuffers.hexDump(ChannelBuffers.wrappedBuffer(bytes, 1, 16)).substring(1);
+ String imei = ChannelBuffers.hexDump(ChannelBuffers.wrappedBuffer(bytes, 1, 8)).substring(1);
if (!identify(imei, channel)) {
return null;
}
- // Send response (CRC)
+ // Send response (checksum)
if (channel != null) {
byte[] response = "resp_crc=".getBytes("US-ASCII");
response = Arrays.copyOf(response, response.length + 1);
response[response.length - 1] = checksum(bytes, 0, 18);
channel.write(ChannelBuffers.wrappedBuffer(response));
}
+
} else if (type == MSG_LOCATION) {
+
buf.readUnsignedByte();
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
short status = buf.readUnsignedByte();
- position.set(Event.KEY_ALARM, (status & 0x80) != 0);
- position.set(Event.KEY_BATTERY, status & 0x7F);
+ position.set(Event.KEY_ALARM, BitUtil.check(status, 7));
+ position.set(Event.KEY_BATTERY, BitUtil.to(status, 7));
buf.skipBytes(2); // remaining time
@@ -94,37 +101,27 @@ public class AutoFon45ProtocolDecoder extends BaseProtocolDecoder {
buf.readByte(); // mode
buf.readByte(); // gprs sending interval
- buf.skipBytes(6); // MCC, MNC, LAC, CID
+ buf.skipBytes(6); // mcc, mnc, lac, cid
- // GPS status
int valid = buf.readUnsignedByte();
- position.setValid((valid & 0xc0) != 0);
- position.set(Event.KEY_SATELLITES, valid & 0x3f);
-
- // Date and time
- int timeOfDay = buf.readUnsignedByte() << 16 | buf.readUnsignedByte() << 8 | buf.readUnsignedByte();
- int date = buf.readUnsignedByte() << 16 | buf.readUnsignedByte() << 8 | buf.readUnsignedByte();
-
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.HOUR_OF_DAY, timeOfDay / 10000);
- time.set(Calendar.MINUTE, (timeOfDay - time.get(Calendar.HOUR_OF_DAY) * 10000) / 100);
- time.set(Calendar.SECOND, (timeOfDay - time.get(Calendar.HOUR_OF_DAY) * 10000 - time.get(Calendar.MINUTE) * 100));
- time.set(Calendar.DAY_OF_MONTH, date / 10000);
- time.set(Calendar.MONTH, (date - time.get(Calendar.DAY_OF_MONTH) * 10000) / 100 - 1);
- time.set(Calendar.YEAR, 2000 + (date - time.get(Calendar.DAY_OF_MONTH) * 10000 - (time.get(Calendar.MONTH) + 1) * 100));
- position.setTime(time.getTime());
-
- // Location
- position.setLatitude(convertCoordinate(buf.readUnsignedByte(),
- buf.readUnsignedByte() << 16 | buf.readUnsignedByte() << 8 | buf.readUnsignedByte()));
- position.setLongitude(convertCoordinate(buf.readUnsignedByte(),
- buf.readUnsignedByte() << 16 | buf.readUnsignedByte() << 8 | buf.readUnsignedByte()));
+ position.setValid(BitUtil.from(valid, 6) != 0);
+ position.set(Event.KEY_SATELLITES, BitUtil.from(valid, 6));
+
+ int time = buf.readUnsignedMedium();
+ int date = buf.readUnsignedMedium();
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setTime(time / 10000, time / 100 % 100, time % 100)
+ .setDateReverse(date / 10000, date / 100 % 100, date % 100);
+ position.setTime(dateBuilder.getDate());
+
+ position.setLatitude(convertCoordinate(buf.readUnsignedByte(), buf.readUnsignedMedium()));
+ position.setLongitude(convertCoordinate(buf.readUnsignedByte(), buf.readUnsignedMedium()));
position.setSpeed(buf.readUnsignedByte());
- position.setCourse(buf.readUnsignedByte() << 8 | buf.readUnsignedByte());
+ position.setCourse(buf.readUnsignedShort());
- buf.readUnsignedByte(); // checksum
return position;
+
}
return null;
diff --git a/src/org/traccar/protocol/AutoFonProtocolDecoder.java b/src/org/traccar/protocol/AutoFonProtocolDecoder.java
index 1da024e0b..9356e2cd7 100644
--- a/src/org/traccar/protocol/AutoFonProtocolDecoder.java
+++ b/src/org/traccar/protocol/AutoFonProtocolDecoder.java
@@ -16,14 +16,13 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
-import java.util.TimeZone;
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.DateBuilder;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -45,7 +44,6 @@ public class AutoFonProtocolDecoder extends BaseProtocolDecoder {
private Position decodePosition(ChannelBuffer buf, boolean history) {
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
@@ -61,7 +59,6 @@ public class AutoFonProtocolDecoder extends BaseProtocolDecoder {
position.set(Event.KEY_BATTERY, buf.readUnsignedByte());
buf.skipBytes(6); // time
- // Timers
if (!history) {
for (int i = 0; i < 2; i++) {
buf.skipBytes(5); // time
@@ -77,23 +74,15 @@ public class AutoFonProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedShort(); // lac
buf.readUnsignedShort(); // cid
- // GPS status
int valid = buf.readUnsignedByte();
position.setValid((valid & 0xc0) != 0);
position.set(Event.KEY_SATELLITES, valid & 0x3f);
- // Date and time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte());
- time.set(Calendar.MONTH, buf.readUnsignedByte() - 1);
- time.set(Calendar.YEAR, 2000 + buf.readUnsignedByte());
- time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte());
- time.set(Calendar.MINUTE, buf.readUnsignedByte());
- time.set(Calendar.SECOND, buf.readUnsignedByte());
- position.setTime(time.getTime());
-
- // Location
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ position.setTime(dateBuilder.getDate());
+
position.setLatitude(convertCoordinate(buf.readInt()));
position.setLongitude(convertCoordinate(buf.readInt()));
position.setAltitude(buf.readShort());
@@ -109,8 +98,7 @@ public class AutoFonProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -126,7 +114,6 @@ public class AutoFonProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- // Send response
if (channel != null) {
channel.write(ChannelBuffers.wrappedBuffer(new byte[] {buf.readByte()}));
}
diff --git a/src/org/traccar/protocol/Avl301ProtocolDecoder.java b/src/org/traccar/protocol/Avl301ProtocolDecoder.java
index f0ad97bf8..67ea223fa 100644
--- a/src/org/traccar/protocol/Avl301ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Avl301ProtocolDecoder.java
@@ -16,12 +16,11 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
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.DateBuilder;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -60,8 +59,7 @@ public class Avl301ProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -81,36 +79,25 @@ public class Avl301ProtocolDecoder extends BaseProtocolDecoder {
} else if (hasDeviceId() && type == MSG_GPS_LBS_STATUS) {
- // Create new position
Position position = new Position();
position.setDeviceId(getDeviceId());
position.setProtocol(getProtocolName());
- // Date and time(6)
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000 + buf.readUnsignedByte());
- time.set(Calendar.MONTH, buf.readUnsignedByte() - 1);
- time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte());
- time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte());
- time.set(Calendar.MINUTE, buf.readUnsignedByte());
- time.set(Calendar.SECOND, buf.readUnsignedByte());
- position.setTime(time.getTime());
-
- // GPS length and Satellites count
- int gpsLength = buf.readUnsignedByte();
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ position.setTime(dateBuilder.getDate());
+
+ int gpsLength = buf.readUnsignedByte(); // gps len and sat
position.set(Event.KEY_SATELLITES, gpsLength & 0xf);
- //Skip Satellite numbers
- buf.skipBytes(1);
+ buf.readUnsignedByte(); // satellites
- // Location
double latitude = buf.readUnsignedInt() / 600000.0;
double longitude = buf.readUnsignedInt() / 600000.0;
- position.setSpeed(buf.readUnsignedByte() * 1.0); // kph?
+ position.setSpeed(buf.readUnsignedByte());
- // Course and flags
- int union = buf.readUnsignedShort();
+ int union = buf.readUnsignedShort(); // course and flags
position.setCourse(union & 0x03FF);
position.setValid((union & 0x1000) != 0);
if ((union & 0x0400) != 0) {
@@ -133,10 +120,11 @@ public class Avl301ProtocolDecoder extends BaseProtocolDecoder {
int flags = buf.readUnsignedByte();
position.set("acc", (flags & 0x2) != 0);
- // TODO parse other flags
+ // parse other flags
position.set(Event.KEY_POWER, buf.readUnsignedByte());
position.set(Event.KEY_GSM, buf.readUnsignedByte());
+
return position;
}
diff --git a/src/org/traccar/protocol/BceProtocolDecoder.java b/src/org/traccar/protocol/BceProtocolDecoder.java
index 31e0868fd..ef70f93d4 100644
--- a/src/org/traccar/protocol/BceProtocolDecoder.java
+++ b/src/org/traccar/protocol/BceProtocolDecoder.java
@@ -44,8 +44,7 @@ public class BceProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
diff --git a/src/org/traccar/protocol/BlackKiteProtocolDecoder.java b/src/org/traccar/protocol/BlackKiteProtocolDecoder.java
index 6b7a8a971..3a32a1dc2 100644
--- a/src/org/traccar/protocol/BlackKiteProtocolDecoder.java
+++ b/src/org/traccar/protocol/BlackKiteProtocolDecoder.java
@@ -66,8 +66,7 @@ public class BlackKiteProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
diff --git a/src/org/traccar/protocol/CalAmpProtocolDecoder.java b/src/org/traccar/protocol/CalAmpProtocolDecoder.java
index 6b959ea82..bd648b0f9 100644
--- a/src/org/traccar/protocol/CalAmpProtocolDecoder.java
+++ b/src/org/traccar/protocol/CalAmpProtocolDecoder.java
@@ -21,6 +21,7 @@ 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.UnitsConverter;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -68,7 +69,6 @@ public class CalAmpProtocolDecoder extends BaseProtocolDecoder {
position.setDeviceId(getDeviceId());
position.setProtocol(getProtocolName());
- // Location data
position.setTime(new Date(buf.readUnsignedInt() * 1000));
if (type != MSG_MINI_EVENT_REPORT) {
buf.readUnsignedInt(); // fix time
@@ -84,7 +84,6 @@ public class CalAmpProtocolDecoder extends BaseProtocolDecoder {
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
}
- // Fix status
if (type == MSG_MINI_EVENT_REPORT) {
position.set(Event.KEY_SATELLITES, buf.getUnsignedByte(buf.readerIndex()) & 0xf);
position.setValid((buf.readUnsignedByte() & 0x20) == 0);
@@ -94,32 +93,22 @@ public class CalAmpProtocolDecoder extends BaseProtocolDecoder {
}
if (type != MSG_MINI_EVENT_REPORT) {
-
- // Carrier
position.set("carrier", buf.readUnsignedShort());
-
- // Cell signal
position.set(Event.KEY_GSM, buf.readShort());
-
}
- // Modem state
position.set("modem", buf.readUnsignedByte());
- // HDOP
if (type != MSG_MINI_EVENT_REPORT) {
position.set(Event.KEY_HDOP, buf.readUnsignedByte());
}
- // Inputs
position.set(Event.KEY_INPUT, buf.readUnsignedByte());
- // Unit status
if (type != MSG_MINI_EVENT_REPORT) {
position.set(Event.KEY_STATUS, buf.readUnsignedByte());
}
- // Event code
if (type == MSG_EVENT_REPORT || type == MSG_MINI_EVENT_REPORT) {
if (type != MSG_MINI_EVENT_REPORT) {
buf.readUnsignedByte(); // event index
@@ -127,10 +116,8 @@ public class CalAmpProtocolDecoder extends BaseProtocolDecoder {
position.set(Event.KEY_EVENT, buf.readUnsignedByte());
}
- // Accumulators
- int accCount = buf.readUnsignedByte();
- int accType = accCount >> 6;
- accCount &= 0x3f;
+ int accType = BitUtil.from(buf.getUnsignedByte(buf.readerIndex()), 6);
+ int accCount = BitUtil.to(buf.readUnsignedByte(), 6);
if (type != MSG_MINI_EVENT_REPORT) {
buf.readUnsignedByte(); // reserved
@@ -150,20 +137,16 @@ public class CalAmpProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
- // Check options header
- if ((buf.getByte(buf.readerIndex()) & 0x80) != 0) {
+ if (BitUtil.check(buf.getByte(buf.readerIndex()), 7)) {
int content = buf.readUnsignedByte();
- // Identifier
- if ((content & 0x01) != 0) {
+ if (BitUtil.check(content, 0)) {
- // Read identifier
int length = buf.readUnsignedByte();
long id = 0;
for (int i = 0; i < length; i++) {
@@ -177,34 +160,28 @@ public class CalAmpProtocolDecoder extends BaseProtocolDecoder {
identify(String.valueOf(id), channel, remoteAddress);
}
- // Identifier type
- if ((content & 0x02) != 0) {
- buf.skipBytes(buf.readUnsignedByte());
+ if (BitUtil.check(content, 1)) {
+ buf.skipBytes(buf.readUnsignedByte()); // identifier type
}
- // Authentication
- if ((content & 0x04) != 0) {
- buf.skipBytes(buf.readUnsignedByte());
+ if (BitUtil.check(content, 2)) {
+ buf.skipBytes(buf.readUnsignedByte()); // authentication
}
- // Routing
- if ((content & 0x08) != 0) {
- buf.skipBytes(buf.readUnsignedByte());
+ if (BitUtil.check(content, 3)) {
+ buf.skipBytes(buf.readUnsignedByte()); // routing
}
- // Forwarding
- if ((content & 0x10) != 0) {
- buf.skipBytes(buf.readUnsignedByte());
+ if (BitUtil.check(content, 4)) {
+ buf.skipBytes(buf.readUnsignedByte()); // forwarding
}
- // Responce redirection
- if ((content & 0x20) != 0) {
- buf.skipBytes(buf.readUnsignedByte());
+ if (BitUtil.check(content, 5)) {
+ buf.skipBytes(buf.readUnsignedByte()); // response redirection
}
}
- // Unidentified device
if (!hasDeviceId()) {
return null;
}
@@ -213,7 +190,6 @@ public class CalAmpProtocolDecoder extends BaseProtocolDecoder {
int type = buf.readUnsignedByte();
int index = buf.readUnsignedShort();
- // Send acknowledgement
if (service == SERVICE_ACKNOWLEDGED) {
sendResponse(channel, remoteAddress, type, index, 0);
}
diff --git a/src/org/traccar/protocol/CarTrackProtocolDecoder.java b/src/org/traccar/protocol/CarTrackProtocolDecoder.java
index d9bf27973..762017d33 100644
--- a/src/org/traccar/protocol/CarTrackProtocolDecoder.java
+++ b/src/org/traccar/protocol/CarTrackProtocolDecoder.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014 Anton Tananaev (anton.tananaev@gmail.com)
- * Rohit
+ * Copyright 2014 - 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2014 Rohit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,12 +17,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
@@ -32,100 +32,63 @@ public class CarTrackProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "\\$\\$" + // Header
- "(\\d+)\\?*" + // Device ID
- "&A" +
- "(\\d{4})" + // Command - 2
- "&B" +
- "(\\d{2})(\\d{2})(\\d{2})\\.(\\d{3})," + // HHMMSS.DDD
- "([AV])," + // STATUS : A= Valid, V = Invalid
- "(\\d{2})(\\d{2}\\.\\d{4})," + // Lat : XXMM.DDDDD
- "([NS])," + // N/S
- "(\\d{3})(\\d{2}\\.\\d{4})," + // Long : YYYMM.DDDD
- "([EW])," + // E/W
- "(\\d+.\\d*)?," + // Speed in Knots
- "(\\d+.\\d*)?," + // Heading
- "(\\d{2})(\\d{2})(\\d{2})" + // DDMMYY
- ".*" +
- "&C(.*)" + // IO Port Data
- "&D(.*)" + // Mile Meter Data
- "&E(.*)" + // Alarm Data
- "(?:&Y)?(.*)"); // AD Input Data
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("$$") // header
+ .number("(d+)") // device id
+ .text("?").expression("*")
+ .text("&A")
+ .number("(dddd)") // command
+ .text("&B")
+ .number("(dd)(dd)(dd).(ddd),") // time
+ .expression("([AV]),") // validity
+ .number("(dd)(dd.dddd),") // latitude
+ .expression("([NS]),")
+ .number("(ddd)(dd.dddd),") // longitude
+ .expression("([EW]),")
+ .number("(d+.d*)?,") // speed
+ .number("(d+.d*)?,") // course
+ .number("(dd)(dd)(dd)") // date (ddmmyy)
+ .any()
+ .expression("&C([^&]*)") // io
+ .expression("&D([^&]*)") // odometer
+ .expression("&E([^&]*)") // alarm
+ .expression("&Y([^&]*)").optional() // adc
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String sentence = (String) msg;
-
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
- // Get device by unique identifier
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Command
- position.set("command", parser.group(index++));
-
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MILLISECOND, Integer.parseInt(parser.group(index++)));
-
- // Validity
- position.setValid(parser.group(index++).compareTo("A") == 0);
-
- // Latitude
- double latitude = Double.parseDouble(parser.group(index++));
- latitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("S") == 0) latitude = -latitude;
- position.setLatitude(latitude);
-
- // Longitude
- double longitude = Double.parseDouble(parser.group(index++));
- longitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("W") == 0) longitude = -longitude;
- position.setLongitude(longitude);
-
- // Speed
- String speed = parser.group(index++);
- if (speed != null) {
- position.setSpeed(Double.parseDouble(speed));
- }
+ position.set("command", parser.next());
- // Course
- String course = parser.group(index++);
- if (course != null) {
- position.setCourse(Double.parseDouble(course));
- }
+ DateBuilder dateBuilder = new DateBuilder()
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt());
- // Date
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
- // State
- position.set(Event.PREFIX_IO + 1, parser.group(index++));
+ dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Odometer
- String odometer = parser.group(index++);
+ position.set(Event.PREFIX_IO + 1, parser.next());
+
+ String odometer = parser.next();
odometer = odometer.replace(":", "A");
odometer = odometer.replace(";", "B");
odometer = odometer.replace("<", "C");
@@ -134,8 +97,9 @@ public class CarTrackProtocolDecoder extends BaseProtocolDecoder {
odometer = odometer.replace("?", "F");
position.set(Event.KEY_ODOMETER, Integer.parseInt(odometer, 16));
- position.set(Event.KEY_ALARM, parser.group(index++));
- position.set("ad", parser.group(index++));
+ position.set(Event.KEY_ALARM, parser.next());
+ position.set(Event.PREFIX_ADC + 1, parser.next());
+
return position;
}
diff --git a/src/org/traccar/protocol/CastelProtocolDecoder.java b/src/org/traccar/protocol/CastelProtocolDecoder.java
index fe8d0a525..7d4182f7c 100644
--- a/src/org/traccar/protocol/CastelProtocolDecoder.java
+++ b/src/org/traccar/protocol/CastelProtocolDecoder.java
@@ -18,15 +18,14 @@ package org.traccar.protocol;
import java.net.SocketAddress;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
-import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
-import java.util.TimeZone;
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.Checksum;
+import org.traccar.helper.DateBuilder;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -37,29 +36,32 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final short MSG_LOGIN = 0x1001;
- private static final short MSG_LOGIN_RESPONSE = (short) 0x9001;
- private static final short MSG_LOGOUT = 0x1002;
- private static final short MSG_HEARTBEAT = 0x1003;
- private static final short MSG_HEARTBEAT_RESPONSE = (short) 0x9003;
- private static final short MSG_GPS = 0x4001;
- private static final short MSG_ALARM = 0x4007;
- private static final short MSG_GPS_SLEEP = 0x4009;
- private static final short MSG_AGPS_REQUEST = 0x5101;
- private static final short MSG_CURRENT_LOCATION = (short) 0xB001;
-
- private static void readPosition(ChannelBuffer buf, Position position) {
-
- // Date and time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte());
- time.set(Calendar.MONTH, buf.readUnsignedByte() - 1);
- time.set(Calendar.YEAR, 2000 + buf.readUnsignedByte());
- time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte());
- time.set(Calendar.MINUTE, buf.readUnsignedByte());
- time.set(Calendar.SECOND, buf.readUnsignedByte());
- position.setTime(time.getTime());
+ private static final short MSG_SC_LOGIN = 0x1001;
+ private static final short MSG_SC_LOGIN_RESPONSE = (short) 0x9001;
+ private static final short MSG_SC_LOGOUT = 0x1002;
+ private static final short MSG_SC_HEARTBEAT = 0x1003;
+ private static final short MSG_SC_HEARTBEAT_RESPONSE = (short) 0x9003;
+ private static final short MSG_SC_GPS = 0x4001;
+ private static final short MSG_SC_ALARM = 0x4007;
+ private static final short MSG_SC_GPS_SLEEP = 0x4009;
+ private static final short MSG_SC_AGPS_REQUEST = 0x5101;
+ private static final short MSG_SC_CURRENT_LOCATION = (short) 0xB001;
+
+ private static final short MSG_CC_LOGIN = 0x4001;
+ private static final short MSG_CC_LOGIN_RESPONSE = (short) 0x8001;
+ private static final short MSG_CC_HEARTBEAT = 0x4206;
+ private static final short MSG_CC_HEARTBEAT_RESPONSE = (short) 0x8206;
+
+ private Position readPosition(ChannelBuffer buf) {
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(getDeviceId());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ position.setTime(dateBuilder.getDate());
double lat = buf.readUnsignedInt() / 3600000.0;
double lon = buf.readUnsignedInt() / 3600000.0;
@@ -77,12 +79,36 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder {
position.setLongitude(lon);
position.setValid((flags & 0x0C) > 0);
position.set(Event.KEY_SATELLITES, flags >> 4);
+
+ return position;
+ }
+
+ private void sendResponse(
+ Channel channel, SocketAddress remoteAddress,
+ int version, ChannelBuffer id, short type, ChannelBuffer content) {
+
+ if (channel != null) {
+ int length = 2 + 2 + 1 + id.readableBytes() + 2 + 2 + 2;
+ if (content != null) {
+ length += content.readableBytes();
+ }
+
+ ChannelBuffer response = ChannelBuffers.directBuffer(ByteOrder.LITTLE_ENDIAN, length);
+ response.writeByte('@'); response.writeByte('@');
+ response.writeShort(length);
+ response.writeByte(version);
+ response.writeBytes(id);
+ response.writeShort(ChannelBuffers.swapShort(type));
+ 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 {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -92,98 +118,117 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder {
ChannelBuffer id = buf.readBytes(20);
int type = ChannelBuffers.swapShort(buf.readShort());
- if (type == MSG_HEARTBEAT) {
-
- if (channel != null) {
- ChannelBuffer response = ChannelBuffers.directBuffer(ByteOrder.LITTLE_ENDIAN, 31);
- response.writeByte(0x40); response.writeByte(0x40);
- response.writeShort(response.capacity());
- response.writeByte(version);
- response.writeBytes(id);
- response.writeShort(ChannelBuffers.swapShort(MSG_HEARTBEAT_RESPONSE));
- response.writeShort(
- Checksum.crc16(Checksum.CRC16_X25, response.toByteBuffer(0, response.writerIndex())));
- response.writeByte(0x0D); response.writeByte(0x0A);
- channel.write(response, remoteAddress);
- }
+ if (!identify(id.toString(Charset.defaultCharset()).trim(), channel, remoteAddress)) {
+ return null;
+ }
- } else if (type == MSG_LOGIN || type == MSG_LOGOUT || type == MSG_GPS
- || type == MSG_ALARM || type == MSG_CURRENT_LOCATION) {
+ if (version == 4) {
- if (!identify(id.toString(Charset.defaultCharset()).trim(), channel, remoteAddress)) {
+ if (type == MSG_SC_HEARTBEAT) {
- return null;
+ sendResponse(channel, remoteAddress, version, id, MSG_SC_HEARTBEAT_RESPONSE, null);
- } else if (type == MSG_LOGIN && channel != null) {
+ } else if (type == MSG_SC_LOGIN || type == MSG_SC_LOGOUT || type == MSG_SC_GPS
+ || type == MSG_SC_ALARM || type == MSG_SC_CURRENT_LOCATION) {
- ChannelBuffer response = ChannelBuffers.directBuffer(ByteOrder.LITTLE_ENDIAN, 41);
- response.writeByte(0x40); response.writeByte(0x40);
- response.writeShort(response.capacity());
- response.writeByte(version);
- response.writeBytes(id);
- response.writeShort(ChannelBuffers.swapShort(MSG_LOGIN_RESPONSE));
- response.writeInt(0xFFFFFFFF);
- response.writeShort(0);
- response.writeInt((int) (System.currentTimeMillis() / 1000));
- response.writeShort(
- Checksum.crc16(Checksum.CRC16_X25, response.toByteBuffer(0, response.writerIndex())));
- response.writeByte(0x0D); response.writeByte(0x0A);
- channel.write(response, remoteAddress);
+ if (type == MSG_SC_LOGIN) {
+ ChannelBuffer response = ChannelBuffers.directBuffer(ByteOrder.LITTLE_ENDIAN, 10);
+ response.writeInt(0xFFFFFFFF);
+ response.writeShort(0);
+ response.writeInt((int) (System.currentTimeMillis() / 1000));
+ sendResponse(channel, remoteAddress, version, id, MSG_SC_LOGIN_RESPONSE, response);
+ }
- }
+ if (type == MSG_SC_GPS) {
+ buf.readUnsignedByte(); // historical
+ } else if (type == MSG_SC_ALARM) {
+ buf.readUnsignedInt(); // alarm
+ } else if (type == MSG_SC_CURRENT_LOCATION) {
+ buf.readUnsignedShort();
+ }
+
+ buf.readUnsignedInt(); // ACC ON time
+ buf.readUnsignedInt(); // UTC time
+ long odometer = buf.readUnsignedInt();
+ buf.readUnsignedInt(); // trip odometer
+ buf.readUnsignedInt(); // total fuel consumption
+ buf.readUnsignedShort(); // current fuel consumption
+ long status = buf.readUnsignedInt();
+ buf.skipBytes(8);
+
+ int count = buf.readUnsignedByte();
+
+ List<Position> positions = new LinkedList<>();
+
+ for (int i = 0; i < count; i++) {
+ Position position = readPosition(buf);
+ position.set(Event.KEY_ODOMETER, odometer);
+ position.set(Event.KEY_STATUS, status);
+ positions.add(position);
+ }
+
+ if (!positions.isEmpty()) {
+ return positions;
+ }
+
+ } else if (type == MSG_SC_GPS_SLEEP || type == MSG_SC_AGPS_REQUEST) {
+
+ return readPosition(buf);
- if (type == MSG_GPS) {
- buf.readUnsignedByte(); // historical
- } else if (type == MSG_ALARM) {
- buf.readUnsignedInt(); // alarm
- } else if (type == MSG_CURRENT_LOCATION) {
- buf.readUnsignedShort();
}
- buf.readUnsignedInt(); // ACC ON time
- buf.readUnsignedInt(); // UTC time
- long odometer = buf.readUnsignedInt();
- buf.readUnsignedInt(); // trip odometer
- buf.readUnsignedInt(); // total fuel consumption
- buf.readUnsignedShort(); // current fuel consumption
- long status = buf.readUnsignedInt();
- buf.skipBytes(8);
+ } else {
- int count = buf.readUnsignedByte();
+ if (type == MSG_CC_HEARTBEAT) {
- List<Position> positions = new LinkedList<>();
+ sendResponse(channel, remoteAddress, version, id, MSG_CC_HEARTBEAT_RESPONSE, null);
- for (int i = 0; i < count; i++) {
+ buf.readUnsignedByte(); // 0x01 for history
+ int count = buf.readUnsignedByte();
- Position position = new Position();
- position.setProtocol(getProtocolName());
- position.setDeviceId(getDeviceId());
+ List<Position> positions = new LinkedList<>();
- readPosition(buf, position);
+ for (int i = 0; i < count; i++) {
+ Position position = readPosition(buf);
- position.set(Event.KEY_ODOMETER, odometer);
- position.set(Event.KEY_STATUS, status);
+ position.set(Event.KEY_STATUS, buf.readUnsignedInt());
+ position.set(Event.KEY_BATTERY, buf.readUnsignedByte());
+ position.set(Event.KEY_ODOMETER, buf.readUnsignedInt());
- positions.add(position);
- }
+ buf.readUnsignedByte(); // geo-fencing id
+ buf.readUnsignedByte(); // geo-fencing flags
+ buf.readUnsignedByte(); // additional flags
+
+ position.set(Event.KEY_LAC, buf.readUnsignedShort());
+ position.set(Event.KEY_CELL, buf.readUnsignedShort());
+
+ positions.add(position);
+ }
- if (!positions.isEmpty()) {
return positions;
- }
- } else if (type == MSG_GPS_SLEEP || type == MSG_AGPS_REQUEST) {
+ } else if (type == MSG_CC_LOGIN) {
- if (!identify(id.toString(Charset.defaultCharset()).trim(), channel, remoteAddress)) {
- return null;
- }
+ sendResponse(channel, remoteAddress, version, id, MSG_CC_LOGIN_RESPONSE, null);
+
+ Position position = readPosition(buf);
+
+ position.set(Event.KEY_STATUS, buf.readUnsignedInt());
+ position.set(Event.KEY_BATTERY, buf.readUnsignedByte());
+ position.set(Event.KEY_ODOMETER, buf.readUnsignedInt());
- Position position = new Position();
- position.setProtocol(getProtocolName());
- position.setDeviceId(getDeviceId());
+ buf.readUnsignedByte(); // geo-fencing id
+ buf.readUnsignedByte(); // geo-fencing flags
+ buf.readUnsignedByte(); // additional flags
- readPosition(buf, position);
+ // GSM_CELL_CODE
+ // STR_Z - firmware version
+ // STR_Z - hardware version
+
+ return position;
+
+ }
- return position;
}
return null;
diff --git a/src/org/traccar/protocol/CellocatorProtocolDecoder.java b/src/org/traccar/protocol/CellocatorProtocolDecoder.java
index 5517e703b..27c94c6ba 100644
--- a/src/org/traccar/protocol/CellocatorProtocolDecoder.java
+++ b/src/org/traccar/protocol/CellocatorProtocolDecoder.java
@@ -17,12 +17,11 @@ package org.traccar.protocol;
import java.net.SocketAddress;
import java.nio.ByteOrder;
-import java.util.Calendar;
-import java.util.TimeZone;
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.DateBuilder;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -70,8 +69,7 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -84,15 +82,13 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder {
}
byte packetNumber = buf.readByte();
- // Send reply
sendReply(channel, deviceUniqueId, packetNumber);
- // Parse location
if (type == MSG_CLIENT_STATUS) {
+
Position position = new Position();
position.setProtocol(getProtocolName());
- // Device identifier
if (!identify(String.valueOf(deviceUniqueId), channel)) {
return null;
}
@@ -102,7 +98,6 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedByte(); // software version
buf.readUnsignedByte(); // protocol version
- // Status
position.set(Event.KEY_STATUS, buf.getUnsignedByte(buf.readerIndex()) & 0x0f);
int operator = (buf.readUnsignedByte() & 0xf0) << 4;
@@ -128,23 +123,17 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder {
position.setValid(buf.readUnsignedByte() >= 3); // satellites
- // Location data
position.setLongitude(buf.readInt() / Math.PI * 180 / 100000000);
position.setLatitude(buf.readInt() / Math.PI * 180 / 100000000.0);
position.setAltitude(buf.readInt() * 0.01);
position.setSpeed(UnitsConverter.knotsFromMps(buf.readInt() * 0.01));
position.setCourse(buf.readUnsignedShort() / Math.PI * 180.0 / 1000.0);
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.SECOND, buf.readUnsignedByte());
- time.set(Calendar.MINUTE, buf.readUnsignedByte());
- time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte());
- time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte());
- time.set(Calendar.MONTH, buf.readUnsignedByte() - 1);
- time.set(Calendar.YEAR, buf.readUnsignedShort());
- position.setTime(time.getTime());
+ DateBuilder dateBuilder = new DateBuilder()
+ .setTimeReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedShort());
+ position.setTime(dateBuilder.getDate());
+
return position;
}
diff --git a/src/org/traccar/protocol/CityeasyProtocolDecoder.java b/src/org/traccar/protocol/CityeasyProtocolDecoder.java
index 67da05a8d..213dd90d0 100644
--- a/src/org/traccar/protocol/CityeasyProtocolDecoder.java
+++ b/src/org/traccar/protocol/CityeasyProtocolDecoder.java
@@ -17,15 +17,15 @@ package org.traccar.protocol;
import java.net.SocketAddress;
import java.nio.charset.Charset;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.Checksum;
+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;
@@ -35,21 +35,24 @@ public class CityeasyProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "(\\d{4})(\\d{2})(\\d{2})" + // Date
- "(\\d{2})(\\d{2})(\\d{2})," + // Time
- "([AV])," + // Validity
- "(\\d+)," + // Satellites
- "([NS]),(\\d+\\.\\d+)," + // Latitude
- "([EW]),(\\d+\\.\\d+)," + // Longitude
- "(\\d+\\.\\d)," + // Speed
- "(\\d+\\.\\d)," + // HDOP
- "(\\d+\\.\\d);" + // Altitude
- "(\\d+)," + // MCC
- "(\\d+)," + // MNC
- "(\\d+)," + // LAC
- "(\\d+)" + // Cell
- ".*");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .groupBegin()
+ .number("(dddd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd),") // time
+ .number("([AV]),") // validity
+ .number("(d+),") // satellites
+ .number("([NS]),(d+.d+),") // latitude
+ .number("([EW]),(d+.d+),") // longitude
+ .number("(d+.d),") // speed
+ .number("(d+.d),") // hdop
+ .number("(d+.d)") // altitude
+ .groupEnd("?").text(";")
+ .number("(d+),") // mcc
+ .number("(d+),") // mnc
+ .number("(d+),") // lac
+ .number("(d+)") // cell
+ .any()
+ .compile();
public static final int MSG_ADDRESS_REQUEST = 0x0001;
public static final int MSG_STATUS = 0x0002;
@@ -62,8 +65,7 @@ public class CityeasyProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -80,7 +82,7 @@ public class CityeasyProtocolDecoder extends BaseProtocolDecoder {
if (type == MSG_LOCATION_REPORT || type == MSG_LOCATION_REQUEST) {
String sentence = buf.toString(buf.readerIndex(), buf.readableBytes() - 8, Charset.defaultCharset());
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
return null;
}
@@ -89,46 +91,33 @@ public class CityeasyProtocolDecoder extends BaseProtocolDecoder {
position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
- Integer index = 1;
-
- // Date and time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
-
- position.setValid(parser.group(index++).equals("A"));
- position.set(Event.KEY_SATELLITES, parser.group(index++));
-
- // Latitude
- String hemisphere = parser.group(index++);
- double latitude = Double.parseDouble(parser.group(index++));
- if (hemisphere.compareTo("S") == 0) {
- latitude = -latitude;
- }
- position.setLatitude(latitude);
+ if (parser.hasNext(15)) {
- // Longitude
- hemisphere = parser.group(index++);
- double longitude = Double.parseDouble(parser.group(index++));
- if (hemisphere.compareTo("W") == 0) {
- longitude = -longitude;
- }
- position.setLongitude(longitude);
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+
+ position.setValid(parser.next().equals("A"));
+ position.set(Event.KEY_SATELLITES, parser.next());
+
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG));
- position.setSpeed(Double.parseDouble(parser.group(index++)));
- position.set(Event.KEY_HDOP, Double.parseDouble(parser.group(index++)));
- position.setAltitude(Double.parseDouble(parser.group(index++)));
+ position.setSpeed(parser.nextDouble());
+ position.set(Event.KEY_HDOP, parser.nextDouble());
+ position.setAltitude(parser.nextDouble());
+
+ } else {
+
+ getLastLocation(position, null);
+
+ }
- position.set(Event.KEY_MCC, Integer.parseInt(parser.group(index++)));
- position.set(Event.KEY_MNC, Integer.parseInt(parser.group(index++)));
- position.set(Event.KEY_LAC, Integer.parseInt(parser.group(index++)));
- position.set(Event.KEY_CELL, Integer.parseInt(parser.group(index++)));
+ position.set(Event.KEY_MCC, parser.nextInt());
+ position.set(Event.KEY_MNC, parser.nextInt());
+ position.set(Event.KEY_LAC, parser.nextInt());
+ position.set(Event.KEY_CELL, parser.nextInt());
return position;
}
diff --git a/src/org/traccar/protocol/EasyTrackProtocolDecoder.java b/src/org/traccar/protocol/EasyTrackProtocolDecoder.java
index 21553fa44..352fc97dc 100644
--- a/src/org/traccar/protocol/EasyTrackProtocolDecoder.java
+++ b/src/org/traccar/protocol/EasyTrackProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2013 - 2015 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,12 +16,13 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
+import org.traccar.helper.BitUtil;
+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;
@@ -31,105 +32,81 @@ public class EasyTrackProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "\\*..," + // Manufacturer
- "(\\d+)," + // IMEI
- "([^,]{2})," + // Command
- "([AV])," + // Validity
- "(\\p{XDigit}{2})" + // Year
- "(\\p{XDigit}{2})" + // Month
- "(\\p{XDigit}{2})," + // Day
- "(\\p{XDigit}{2})" + // Hours
- "(\\p{XDigit}{2})" + // Minutes
- "(\\p{XDigit}{2})," + // Seconds
- "(\\p{XDigit})" +
- "(\\p{XDigit}{7})," + // Latitude
- "(\\p{XDigit})" +
- "(\\p{XDigit}{7})," + // Longitude
- "(\\p{XDigit}{4})," + // Speed
- "(\\p{XDigit}{4})," + // Course
- "(\\p{XDigit}{8})," + // Status
- "(\\p{XDigit}+)," + // Signal
- "(\\d+)," + // Power
- "(\\p{XDigit}{4})," + // Oil
- "(\\p{XDigit}+),?" + // Odometer
- "(\\d+)?" + // Altitude
- ".*");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("*").expression("..,") // manufacturer
+ .number("(d+),") // imei
+ .expression("([^,]{2}),") // command
+ .expression("([AV]),") // validity
+ .number("(xx)") // year
+ .number("(xx)") // month
+ .number("(xx),") // day
+ .number("(xx)") // hours
+ .number("(xx)") // minutes
+ .number("(xx),") // seconds
+ .number("(x)")
+ .number("(x{7}),") // latitude
+ .number("(x)")
+ .number("(x{7}),") // longitude
+ .number("(x{4}),") // speed
+ .number("(x{4}),") // course
+ .number("(x{8}),") // status
+ .number("(x+),") // signal
+ .number("(d+),") // power
+ .number("(x{4}),") // oil
+ .number("(x+),?") // odometer
+ .number("(d+)?") // altitude
+ .any()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String sentence = (String) msg;
-
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
-
- // Get device by IMEI
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Command
- position.set("command", parser.group(index++));
-
- // Validity
- position.setValid(parser.group(index++).compareTo("A") == 0);
-
- // Date
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++), 16));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++), 16) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++), 16));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++), 16));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++), 16));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++), 16));
- position.setTime(time.getTime());
+ position.set("command", parser.next());
- // Location
- int hemisphere = parser.group(index++).equals("8") ? -1 : 1;
- position.setLatitude(
- hemisphere * Integer.parseInt(parser.group(index++), 16) / 600000.0);
+ position.setValid(parser.next().equals("A"));
- hemisphere = parser.group(index++).equals("8") ? -1 : 1;
- position.setLongitude(
- hemisphere * Integer.parseInt(parser.group(index++), 16) / 600000.0);
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(16), parser.nextInt(16), parser.nextInt(16))
+ .setTime(parser.nextInt(16), parser.nextInt(16), parser.nextInt(16));
+ position.setTime(dateBuilder.getDate());
- position.setSpeed(Integer.parseInt(parser.group(index++), 16) / 100.0);
- position.setCourse(Integer.parseInt(parser.group(index++), 16) / 100.0);
-
- // Status
- position.set(Event.KEY_STATUS, parser.group(index++));
+ if (BitUtil.check(parser.nextInt(16), 7)) {
+ position.setLatitude(-parser.nextInt(16) / 600000.0);
+ } else {
+ position.setLatitude(parser.nextInt(16) / 600000.0);
+ }
- // Signal
- position.set("signal", parser.group(index++));
+ if (BitUtil.check(parser.nextInt(16), 7)) {
+ position.setLongitude(-parser.nextInt(16) / 600000.0);
+ } else {
+ position.setLongitude(parser.nextInt(16) / 600000.0);
+ }
- // Power
- position.set(Event.KEY_POWER, Double.parseDouble(parser.group(index++)));
+ position.setSpeed(parser.nextInt(16) / 100.0);
+ position.setCourse(parser.nextInt(16) / 100.0);
- // Oil
- position.set("oil", Integer.parseInt(parser.group(index++), 16));
+ position.set(Event.KEY_STATUS, parser.next());
+ position.set("signal", parser.next());
+ position.set(Event.KEY_POWER, parser.nextDouble());
+ position.set("oil", parser.nextInt(16));
+ position.set(Event.KEY_ODOMETER, parser.nextInt(16));
- // Odometer
- position.set(Event.KEY_ODOMETER, Integer.parseInt(parser.group(index++), 16));
+ position.setAltitude(parser.nextDouble());
- // Altitude
- String altitude = parser.group(index++);
- if (altitude != null) {
- position.setAltitude(Double.parseDouble(altitude));
- }
return position;
}
diff --git a/src/org/traccar/protocol/EelinkProtocolDecoder.java b/src/org/traccar/protocol/EelinkProtocolDecoder.java
index 0106e6049..6d77abc1b 100644
--- a/src/org/traccar/protocol/EelinkProtocolDecoder.java
+++ b/src/org/traccar/protocol/EelinkProtocolDecoder.java
@@ -54,8 +54,7 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -75,24 +74,20 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
} else if (hasDeviceId()
&& (type == MSG_GPS || type == MSG_ALARM || type == MSG_STATE || type == MSG_SMS)) {
- // Create new position
Position position = new Position();
position.setDeviceId(getDeviceId());
position.setProtocol(getProtocolName());
position.set(Event.KEY_INDEX, index);
- // Location
position.setTime(new Date(buf.readUnsignedInt() * 1000));
position.setLatitude(buf.readInt() / 1800000.0);
position.setLongitude(buf.readInt() / 1800000.0);
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
position.setCourse(buf.readUnsignedShort());
- // Cell
position.set(Event.KEY_CELL, ChannelBuffers.hexDump(buf.readBytes(9)));
- // Validity
position.setValid((buf.readUnsignedByte() & 0x01) != 0);
if (type == MSG_ALARM) {
@@ -102,7 +97,9 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
if (type == MSG_STATE) {
position.set(Event.KEY_STATUS, buf.readUnsignedByte());
}
+
return position;
+
}
return null;
diff --git a/src/org/traccar/protocol/EnforaProtocolDecoder.java b/src/org/traccar/protocol/EnforaProtocolDecoder.java
index ef34d6607..424182da9 100644
--- a/src/org/traccar/protocol/EnforaProtocolDecoder.java
+++ b/src/org/traccar/protocol/EnforaProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2012 - 2015 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,14 +17,14 @@ package org.traccar.protocol;
import java.net.SocketAddress;
import java.nio.charset.Charset;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBufferIndexFinder;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.helper.Log;
+import org.traccar.helper.DateBuilder;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
import org.traccar.helper.StringFinder;
import org.traccar.model.Position;
@@ -34,110 +34,80 @@ public class EnforaProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "GPRMC," +
- "(\\d{2})(\\d{2})(\\d{2}).(\\d+)," + // Time (HHMMSS.SS)
- "([AV])," + // Validity
- "(\\d{2})(\\d{2}.\\d+)," + // Latitude (DDMM.MMMMMM)
- "([NS])," +
- "(\\d{3})(\\d{2}.\\d+)," + // Longitude (DDDMM.MMMMMM)
- "([EW])," +
- "(\\d+.\\d+)?," + // Speed
- "(\\d+.\\d+)?," + // Course
- "(\\d{2})(\\d{2})(\\d{2})," + // Date (DDMMYY)
- ".*[\r\n\u0000]*");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("GPRMC,")
+ .number("(dd)(dd)(dd).(d+),") // time
+ .expression("([AV]),") // validity
+ .number("(dd)(dd.d+),") // latitude
+ .expression("([NS]),")
+ .number("(ddd)(dd.d+),") // longitude
+ .expression("([EW]),")
+ .number("(d+.d+)?,") // speed
+ .number("(d+.d+)?,") // course
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .any()
+ .compile();
public static final int IMEI_LENGTH = 15;
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
- // Find IMEI (Modem ID)
- String imei = null;
- for (int first = -1, i = 0; i < buf.readableBytes(); i++) {
- if (!Character.isDigit((char) buf.getByte(i))) {
- first = i + 1;
- }
-
- // Found digit string
- if (i - first == IMEI_LENGTH - 1) {
- imei = buf.toString(first, IMEI_LENGTH, Charset.defaultCharset());
- break;
+ // Find IMEI number
+ int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), new ChannelBufferIndexFinder() {
+ @Override
+ public boolean find(ChannelBuffer buffer, int guessedIndex) {
+ if (buffer.writerIndex() - guessedIndex >= IMEI_LENGTH) {
+ for (int i = 0; i < IMEI_LENGTH; i++) {
+ if (!Character.isDigit((char) buffer.getByte(guessedIndex + i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
}
+ });
+ if (index == -1) {
+ return null;
}
- // Write log
- if (imei == null) {
- Log.warning("Enfora decoder failed to find IMEI");
+ String imei = buf.toString(index, IMEI_LENGTH, Charset.defaultCharset());
+ if (!identify(imei, channel)) {
return null;
}
- // Find GPSMC string
+ // Find NMEA sentence
int start = buf.indexOf(buf.readerIndex(), buf.writerIndex(), new StringFinder("GPRMC"));
if (start == -1) {
- // Message does not contain GPS data
return null;
}
- String sentence = buf.toString(start, buf.readableBytes() - start, Charset.defaultCharset());
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ String sentence = buf.toString(start, buf.readableBytes() - start, Charset.defaultCharset());
+ Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
-
- // Get device by IMEI
- if (!identify(imei, channel)) {
- return null;
- }
position.setDeviceId(getDeviceId());
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MILLISECOND, Integer.parseInt(parser.group(index++)) * 10);
-
- // Validity
- position.setValid(parser.group(index++).compareTo("A") == 0);
-
- // Latitude
- double latitude = Double.parseDouble(parser.group(index++));
- latitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("S") == 0) latitude = -latitude;
- position.setLatitude(latitude);
-
- // Longitude
- double longitude = Double.parseDouble(parser.group(index++));
- longitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("W") == 0) longitude = -longitude;
- position.setLongitude(longitude);
-
- // Speed
- position.setSpeed(Double.parseDouble(parser.group(index++)));
-
- // Course
- String course = parser.group(index++);
- if (course != null) {
- position.setCourse(Double.parseDouble(course));
- }
+ DateBuilder dateBuilder = new DateBuilder()
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt());
+
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
+
+ dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Date
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
return position;
}
diff --git a/src/org/traccar/protocol/Ev603ProtocolDecoder.java b/src/org/traccar/protocol/Ev603ProtocolDecoder.java
deleted file mode 100644
index 451aff7f2..000000000
--- a/src/org/traccar/protocol/Ev603ProtocolDecoder.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2012 - 2013 Anton Tananaev (anton.tananaev@gmail.com)
- * Luis Parada (luis.parada@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 java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.jboss.netty.channel.Channel;
-import org.traccar.BaseProtocolDecoder;
-import org.traccar.model.Position;
-
-public class Ev603ProtocolDecoder extends BaseProtocolDecoder {
-
- public Ev603ProtocolDecoder(Ev603Protocol protocol) {
- super(protocol);
- }
-
- private static final Pattern PATTERN = Pattern.compile(
- "!.," + // Type
- "(\\d{2})/(\\d{2})/(\\d{2})," + // Date dd/mm/YY
- "(\\d{2}):(\\d{2}):(\\d{2})," + // Time hh:mm:ss
- "(-?\\d+\\.\\d+)," + // Latitude
- "(-?\\d+\\.\\d+)," + // Longitude
- "(\\d+\\.?\\d*)," + // Speed
- "(\\d+\\.?\\d*)," + // Course
- ".*");
-
- @Override
- protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
-
- String sentence = (String) msg;
-
- // Detect device ID
- if (sentence.startsWith("!1,")) {
-
- identify(sentence.substring(3), channel);
-
- } else {
-
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
- if (!hasDeviceId() || !parser.matches()) {
- return null;
- }
-
- // Create new position
- Position position = new Position();
- position.setDeviceId(getDeviceId());
- position.setProtocol(getProtocolName());
- Integer index = 1;
-
- // Date
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
-
- // Time
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
-
- // Validity
- position.setValid(true);
-
- // Coordinates
- position.setLatitude(Double.parseDouble(parser.group(index++)));
- position.setLongitude(Double.parseDouble(parser.group(index++)));
-
- // Speed
- position.setSpeed(Double.parseDouble(parser.group(index++)));
-
- // Course
- position.setCourse(Double.parseDouble(parser.group(index++)));
- if (position.getCourse() > 360) {
- position.setCourse(0);
- }
- return position;
- }
-
- return null;
- }
-}
diff --git a/src/org/traccar/protocol/FlextrackProtocolDecoder.java b/src/org/traccar/protocol/FlextrackProtocolDecoder.java
index e89e31aaf..a8acc42be 100644
--- a/src/org/traccar/protocol/FlextrackProtocolDecoder.java
+++ b/src/org/traccar/protocol/FlextrackProtocolDecoder.java
@@ -16,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
@@ -32,34 +32,36 @@ public class FlextrackProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN_LOGON = Pattern.compile(
- "(-?\\d+)," + // Index
- "LOGON," +
- "(\\d+)," + // Node ID
- "(\\d+)"); // ICCID
-
- private static final Pattern PATTERN = Pattern.compile(
- "(-?\\d+)," + // Index
- "UNITSTAT," +
- "(\\d{4})(\\d{2})(\\d{2})," + // Date (YYYYMMDD)
- "(\\d{2})(\\d{2})(\\d{2})," + // Time (HHMMSS)
- "\\d+," + // Node ID
- "([NS])(\\d+)\\.(\\d+\\.\\d+)," + // Longitude
- "([EW])(\\d+)\\.(\\d+\\.\\d+)," + // Latitude
- "(\\d+)," + // Speed
- "(\\d+)," + // Course
- "(\\d+)," + // Satellites
- "(\\d+)," + // Battery
- "(-?\\d+)," + // GSM
- "(\\p{XDigit}+)," + // State
- "(\\d{3})" + // MCC
- "(\\d{2})," + // MNC
- "(-?\\d+)," + // Altitude
- "(\\d+)," + // HDOP
- "(\\p{XDigit}+)," + // Cell
- "\\d+," + // GPS fix time
- "(\\p{XDigit}+)," + // LAC
- "(\\d+)"); // Odometer
+ private static final Pattern PATTERN_LOGON = new PatternBuilder()
+ .number("(-?d+),") // index
+ .text("LOGON,")
+ .number("(d+),") // node id
+ .number("(d+)") // iccid
+ .compile();
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .number("(-?d+),") // index
+ .text("UNITSTAT,")
+ .number("(dddd)(dd)(dd),") // date
+ .number("(dd)(dd)(dd),") // time
+ .number("d+,") // node id
+ .number("([NS])(d+).(d+.d+),") // latitude
+ .number("([EW])(d+).(d+.d+),") // longitude
+ .number("(d+),") // speed
+ .number("(d+),") // course
+ .number("(d+),") // satellites
+ .number("(d+),") // battery
+ .number("(-?d+),") // gsm
+ .number("(x+),") // state
+ .number("(ddd)") // mcc
+ .number("(dd),") // mnc
+ .number("(-?d+),") // altitude
+ .number("(d+),") // hdop
+ .number("(x+),") // cell
+ .number("d+,") // gps fix time
+ .number("(x+),") // lac
+ .number("(d+)") // odometer
+ .compile();
private void sendAcknowledgement(Channel channel, String index) {
if (channel != null) {
@@ -69,24 +71,21 @@ public class FlextrackProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
if (sentence.contains("LOGON")) {
- Matcher parser = PATTERN_LOGON.matcher(sentence);
+ Parser parser = new Parser(PATTERN_LOGON, sentence);
if (!parser.matches()) {
return null;
}
- int index = 1;
+ sendAcknowledgement(channel, parser.next());
- sendAcknowledgement(channel, parser.group(index++));
-
- String id = parser.group(index++);
- String iccid = parser.group(index++);
+ String id = parser.next();
+ String iccid = parser.next();
if (!identify(iccid, channel, null, false) && !identify(id, channel)) {
return null;
@@ -94,7 +93,7 @@ public class FlextrackProtocolDecoder extends BaseProtocolDecoder {
} else if (sentence.contains("UNITSTAT") && hasDeviceId()) {
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
return null;
}
@@ -103,56 +102,32 @@ public class FlextrackProtocolDecoder extends BaseProtocolDecoder {
position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
- int index = 1;
-
- sendAcknowledgement(channel, parser.group(index++));
-
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
-
- // Latitude
- String hemisphere = parser.group(index++);
- double lat = Integer.parseInt(parser.group(index++));
- lat += Double.parseDouble(parser.group(index++)) / 60;
- if (hemisphere.equals("S")) {
- lat = -lat;
- }
- position.setLatitude(lat);
-
- // Longitude
- hemisphere = parser.group(index++);
- double lon = Integer.parseInt(parser.group(index++));
- lon += Double.parseDouble(parser.group(index++)) / 60;
- if (hemisphere.equals("W")) {
- lon = -lon;
- }
- position.setLongitude(lon);
+ sendAcknowledgement(channel, parser.next());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
position.setValid(true);
- position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(parser.group(index++))));
- position.setCourse(Integer.parseInt(parser.group(index++)));
-
- position.set(Event.KEY_SATELLITES, Integer.parseInt(parser.group(index++)));
- position.set(Event.KEY_BATTERY, Integer.parseInt(parser.group(index++)));
- position.set(Event.KEY_GSM, Integer.parseInt(parser.group(index++)));
- position.set(Event.KEY_STATUS, Integer.parseInt(parser.group(index++), 16));
- position.set(Event.KEY_MCC, Integer.parseInt(parser.group(index++)));
- position.set(Event.KEY_MNC, Integer.parseInt(parser.group(index++)));
-
- position.setAltitude(Integer.parseInt(parser.group(index++)));
-
- position.set(Event.KEY_HDOP, Integer.parseInt(parser.group(index++)) / 10.0);
- position.set(Event.KEY_CELL, parser.group(index++));
- position.set(Event.KEY_LAC, parser.group(index++));
- position.set(Event.KEY_ODOMETER, Integer.parseInt(parser.group(index++)));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt()));
+ position.setCourse(parser.nextInt());
+
+ position.set(Event.KEY_SATELLITES, parser.nextInt());
+ position.set(Event.KEY_BATTERY, parser.nextInt());
+ position.set(Event.KEY_GSM, parser.nextInt());
+ position.set(Event.KEY_STATUS, parser.nextInt(16));
+ position.set(Event.KEY_MCC, parser.nextInt());
+ position.set(Event.KEY_MNC, parser.nextInt());
+
+ position.setAltitude(parser.nextInt());
+
+ position.set(Event.KEY_HDOP, parser.nextInt() * 0.1);
+ position.set(Event.KEY_CELL, parser.next());
+ position.set(Event.KEY_LAC, parser.next());
+ position.set(Event.KEY_ODOMETER, parser.nextInt());
return position;
}
diff --git a/src/org/traccar/protocol/FreedomProtocolDecoder.java b/src/org/traccar/protocol/FreedomProtocolDecoder.java
index c5ef5a146..e5f0dceee 100644
--- a/src/org/traccar/protocol/FreedomProtocolDecoder.java
+++ b/src/org/traccar/protocol/FreedomProtocolDecoder.java
@@ -45,8 +45,7 @@ public class FreedomProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
diff --git a/src/org/traccar/protocol/GalileoProtocolDecoder.java b/src/org/traccar/protocol/GalileoProtocolDecoder.java
index ea8ac08e7..ce8716291 100644
--- a/src/org/traccar/protocol/GalileoProtocolDecoder.java
+++ b/src/org/traccar/protocol/GalileoProtocolDecoder.java
@@ -112,8 +112,7 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -123,8 +122,8 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
List<Position> positions = new LinkedList<>();
Set<Integer> tags = new HashSet<>();
boolean hasLocation = false;
+
Position position = new Position();
- position.setProtocol(getProtocolName());
while (buf.readerIndex() < length) {
@@ -202,6 +201,7 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
sendReply(channel, buf.readUnsignedShort());
for (Position p : positions) {
+ p.setProtocol(getProtocolName());
p.setDeviceId(getDeviceId());
}
diff --git a/src/org/traccar/protocol/GatorProtocolDecoder.java b/src/org/traccar/protocol/GatorProtocolDecoder.java
index 2bf10b14c..aad771099 100644
--- a/src/org/traccar/protocol/GatorProtocolDecoder.java
+++ b/src/org/traccar/protocol/GatorProtocolDecoder.java
@@ -16,12 +16,11 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.helper.ChannelBufferTools;
+import org.traccar.helper.DateBuilder;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -57,8 +56,7 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -81,42 +79,30 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder {
}
position.setDeviceId(getDeviceId());
- // Date and time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000 + ChannelBufferTools.readHexInteger(buf, 2));
- time.set(Calendar.MONTH, ChannelBufferTools.readHexInteger(buf, 2) - 1);
- time.set(Calendar.DAY_OF_MONTH, ChannelBufferTools.readHexInteger(buf, 2));
- time.set(Calendar.HOUR_OF_DAY, ChannelBufferTools.readHexInteger(buf, 2));
- time.set(Calendar.MINUTE, ChannelBufferTools.readHexInteger(buf, 2));
- time.set(Calendar.SECOND, ChannelBufferTools.readHexInteger(buf, 2));
- position.setTime(time.getTime());
-
- // Location
+ DateBuilder dateBuilder = new DateBuilder()
+ .setYear(ChannelBufferTools.readHexInteger(buf, 2))
+ .setMonth(ChannelBufferTools.readHexInteger(buf, 2))
+ .setDay(ChannelBufferTools.readHexInteger(buf, 2))
+ .setHour(ChannelBufferTools.readHexInteger(buf, 2))
+ .setMinute(ChannelBufferTools.readHexInteger(buf, 2))
+ .setSecond(ChannelBufferTools.readHexInteger(buf, 2));
+ position.setTime(dateBuilder.getDate());
+
position.setLatitude(ChannelBufferTools.readCoordinate(buf));
position.setLongitude(ChannelBufferTools.readCoordinate(buf));
position.setSpeed(UnitsConverter.knotsFromKph(ChannelBufferTools.readHexInteger(buf, 4)));
position.setCourse(ChannelBufferTools.readHexInteger(buf, 4));
- // Flags
int flags = buf.readUnsignedByte();
position.setValid((flags & 0x80) != 0);
position.set(Event.KEY_SATELLITES, flags & 0x0f);
- // Status
position.set(Event.KEY_STATUS, buf.readUnsignedByte());
-
- // Key switch
position.set("key", buf.readUnsignedByte());
-
- // Oil
position.set("oil", buf.readUnsignedShort() / 10.0);
-
- // Power
position.set(Event.KEY_POWER, buf.readUnsignedByte() + buf.readUnsignedByte() / 100.0);
-
- // Odometer
position.set(Event.KEY_ODOMETER, buf.readUnsignedInt());
+
return position;
}
diff --git a/src/org/traccar/protocol/Gl100ProtocolDecoder.java b/src/org/traccar/protocol/Gl100ProtocolDecoder.java
index db22fdb34..2995230ee 100644
--- a/src/org/traccar/protocol/Gl100ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gl100ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2013 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2012 - 2015 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,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.Position;
public class Gl100ProtocolDecoder extends BaseProtocolDecoder {
@@ -30,77 +30,66 @@ public class Gl100ProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "\\+RESP:GT...," +
- "(\\d{15})," + // IMEI
- "(?:(?:\\d+," + // Number
- "\\d," + // Reserved / Geofence id
- "\\d)|" + // Reserved / Geofence alert
- "(?:[^,]*))," + // Calling number
- "([01])," + // GPS fix
- "(\\d+.\\d)," + // Speed
- "(\\d+)," + // Course
- "(-?\\d+.\\d)," + // Altitude
- "\\d*," + // GPS accuracy
- "(-?\\d+.\\d+)," + // Longitude
- "(-?\\d+.\\d+)," + // Latitude
- "(\\d{4})(\\d{2})(\\d{2})" + // Date (YYYYMMDD)
- "(\\d{2})(\\d{2})(\\d{2})," + // Time (HHMMSS)
- ".*");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("+RESP:")
+ .expression("GT...,")
+ .number("(d{15}),") // imei
+ .groupBegin()
+ .number("d+,") // number
+ .number("d,") // reserved / geofence id
+ .number("d") // reserved / geofence alert
+ .or()
+ .number("[^,]*") // calling number
+ .groupEnd(",")
+ .expression("([01]),") // gps fix
+ .number("(d+.d),") // speed
+ .number("(d+),") // course
+ .number("(-?d+.d),") // altitude
+ .number("d*,") // gps accuracy
+ .number("(-?d+.d+),") // longitude
+ .number("(-?d+.d+),") // latitude
+ .number("(dddd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd),") // time
+ .any()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
- // Send response
if (sentence.contains("AT+GTHBD=") && channel != null) {
String response = "+RESP:GTHBD,GPRS ACTIVE,";
response += sentence.substring(9, sentence.lastIndexOf(','));
response += '\0';
- channel.write(response);
+ channel.write(response); // heartbeat response
}
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
-
- // Get device by IMEI
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Validity
- position.setValid(Integer.parseInt(parser.group(index++)) == 0);
-
- // Position info
- position.setSpeed(Double.parseDouble(parser.group(index++)));
- position.setCourse(Double.parseDouble(parser.group(index++)));
- position.setAltitude(Double.parseDouble(parser.group(index++)));
- position.setLongitude(Double.parseDouble(parser.group(index++)));
- position.setLatitude(Double.parseDouble(parser.group(index++)));
-
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
+ position.setValid(parser.nextInt() == 0);
+ position.setSpeed(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());
return position;
}
diff --git a/src/org/traccar/protocol/Gl200ProtocolDecoder.java b/src/org/traccar/protocol/Gl200ProtocolDecoder.java
index a0d8bd1b2..bf481667e 100644
--- a/src/org/traccar/protocol/Gl200ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gl200ProtocolDecoder.java
@@ -131,7 +131,9 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- Parser parser = new Parser(PATTERN_HEARTBEAT, (String) msg);
+ String sentence = (String) msg;
+
+ Parser parser = new Parser(PATTERN_HEARTBEAT, sentence);
if (parser.matches()) {
if (channel != null) {
channel.write("+SACK:GTHBD," + parser.next() + "," + parser.next() + "$", remoteAddress);
@@ -139,7 +141,7 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- parser = new Parser(PATTERN_INF, (String) msg);
+ parser = new Parser(PATTERN_INF, sentence);
if (parser.matches()) {
Position position = new Position();
@@ -166,7 +168,7 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
- parser = new Parser(PATTERN, (String) msg);
+ parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
return null;
}
@@ -179,6 +181,11 @@ 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());
diff --git a/src/org/traccar/protocol/GlobalSatProtocolDecoder.java b/src/org/traccar/protocol/GlobalSatProtocolDecoder.java
index b4c64f750..2643b6375 100644
--- a/src/org/traccar/protocol/GlobalSatProtocolDecoder.java
+++ b/src/org/traccar/protocol/GlobalSatProtocolDecoder.java
@@ -53,7 +53,6 @@ public class GlobalSatProtocolDecoder extends BaseProtocolDecoder {
channel.write("ACK\r");
}
- // Message type
String format;
if (sentence.startsWith("GSr")) {
format = format0;
@@ -230,8 +229,7 @@ public class GlobalSatProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
diff --git a/src/org/traccar/protocol/GoSafeProtocolDecoder.java b/src/org/traccar/protocol/GoSafeProtocolDecoder.java
index de6a6f425..2fb7522d3 100644
--- a/src/org/traccar/protocol/GoSafeProtocolDecoder.java
+++ b/src/org/traccar/protocol/GoSafeProtocolDecoder.java
@@ -22,7 +22,10 @@ import java.util.List;
import java.util.regex.Pattern;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.helper.*;
+import org.traccar.helper.BitUtil;
+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;
@@ -100,6 +103,7 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder {
private Position decodePosition(Parser parser, Date time) {
Position position = new Position();
+ position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
position.setTime(time);
diff --git a/src/org/traccar/protocol/GotopProtocolDecoder.java b/src/org/traccar/protocol/GotopProtocolDecoder.java
index 16348cb7f..cfae1b0f6 100644
--- a/src/org/traccar/protocol/GotopProtocolDecoder.java
+++ b/src/org/traccar/protocol/GotopProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2013 - 2015 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,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
@@ -32,77 +32,52 @@ public class GotopProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "(\\d+)," + // IMEI
- "[^,]+," + // Type
- "([AV])," + // Validity
- "DATE:(\\d{2})(\\d{2})(\\d{2})," + // Date (YYMMDD)
- "TIME:(\\d{2})(\\d{2})(\\d{2})," + // Time (HHMMSS)
- "LAT:(\\d+.\\d+)([NS])," + // Latitude
- "LOT:(\\d+.\\d+)([EW])," + // Longitude
- "Speed:(\\d+.\\d+)," + // Speed
- "([^,]+)," + // Status
- "(\\d+)?" + // Course
- ".*");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .number("(d+),") // imei
+ .expression("[^,]+,") // type
+ .expression("([AV]),") // validity
+ .number("DATE:(dd)(dd)(dd),") // date (yyddmm)
+ .number("TIME:(dd)(dd)(dd),") // time
+ .number("LAT:(d+.d+)([NS]),") // latitude
+ .number("LOT:(d+.d+)([EW]),") // longitude
+ .text("Speed:").number("(d+.d+),") // speed
+ .expression("([^,]+),") // status
+ .number("(d+)?") // course
+ .any()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- // Parse message
- String sentence = (String) msg;
- Matcher parser = PATTERN.matcher(sentence);
- if (sentence.isEmpty() || !parser.matches()) {
+ Parser parser = new Parser(PATTERN, (String) msg);
+ if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
- // Get device by IMEI
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Validity
- position.setValid(parser.group(index++).compareTo("A") == 0);
+ position.setValid(parser.next().equals("A"));
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Latitude
- Double latitude = Double.parseDouble(parser.group(index++));
- if (parser.group(index++).compareTo("S") == 0) latitude = -latitude;
- position.setLatitude(latitude);
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
- // Longitude
- Double longitude = Double.parseDouble(parser.group(index++));
- if (parser.group(index++).compareTo("W") == 0) longitude = -longitude;
- position.setLongitude(longitude);
+ position.set(Event.KEY_STATUS, parser.next());
- // Speed
- position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(parser.group(index++))));
+ position.setCourse(parser.nextDouble());
- // Status
- position.set(Event.KEY_STATUS, parser.group(index++));
-
- // Course
- String course = parser.group(index++);
- if (course != null) {
- position.setCourse(Double.parseDouble(course));
- }
return position;
}
diff --git a/src/org/traccar/protocol/Gps103Protocol.java b/src/org/traccar/protocol/Gps103Protocol.java
index dcac04c5b..35515e2e7 100644
--- a/src/org/traccar/protocol/Gps103Protocol.java
+++ b/src/org/traccar/protocol/Gps103Protocol.java
@@ -35,7 +35,8 @@ public class Gps103Protocol extends BaseProtocol {
Command.TYPE_POSITION_PERIODIC,
Command.TYPE_POSITION_STOP,
Command.TYPE_ENGINE_STOP,
- Command.TYPE_ENGINE_RESUME);
+ Command.TYPE_ENGINE_RESUME,
+ Command.TYPE_REQUEST_PHOTO);
}
@Override
diff --git a/src/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/org/traccar/protocol/Gps103ProtocolDecoder.java
index 9fa71ad58..aa693f42e 100644
--- a/src/org/traccar/protocol/Gps103ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gps103ProtocolDecoder.java
@@ -69,8 +69,7 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
@@ -102,7 +101,6 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position();
position.setProtocol(getProtocolName());
- // Get device by IMEI
String imei = parser.next();
if (!identify(imei, channel, remoteAddress)) {
return null;
@@ -121,15 +119,15 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
int localHours = parser.nextInt();
int localMinutes = parser.nextInt();
- int utcHours = parser.nextInt();
- int utcMinutes = parser.nextInt();
+ String utcHours = parser.next();
+ String utcMinutes = parser.next();
dateBuilder.setTime(localHours, localMinutes, parser.nextInt(), parser.nextInt());
// Timezone calculation
- if (utcHours != 0 && utcMinutes != 0) {
- int deltaMinutes = (localHours - utcHours) * 60;
- deltaMinutes += localMinutes - utcMinutes;
+ if (utcHours != null && utcMinutes != null) {
+ int deltaMinutes = (localHours - Integer.parseInt(utcHours)) * 60;
+ deltaMinutes += localMinutes - Integer.parseInt(utcMinutes);
if (deltaMinutes <= -12 * 60) {
deltaMinutes += 24 * 60;
} else if (deltaMinutes > 12 * 60) {
diff --git a/src/org/traccar/protocol/Gps103ProtocolEncoder.java b/src/org/traccar/protocol/Gps103ProtocolEncoder.java
index 9f0df8761..23942e554 100644
--- a/src/org/traccar/protocol/Gps103ProtocolEncoder.java
+++ b/src/org/traccar/protocol/Gps103ProtocolEncoder.java
@@ -57,6 +57,8 @@ public class Gps103ProtocolEncoder extends StringProtocolEncoder implements Stri
return formatCommand(command, "**,imei:{%s},L", Command.KEY_UNIQUE_ID);
case Command.TYPE_ALARM_DISARM:
return formatCommand(command, "**,imei:{%s},M", Command.KEY_UNIQUE_ID);
+ case Command.TYPE_REQUEST_PHOTO:
+ return formatCommand(command, "**,imei:{%s},160", Command.KEY_UNIQUE_ID);
default:
Log.warning(new UnsupportedOperationException(command.getType()));
break;
diff --git a/src/org/traccar/protocol/GpsGateProtocolDecoder.java b/src/org/traccar/protocol/GpsGateProtocolDecoder.java
index 5e97a66f8..6c0d663d4 100644
--- a/src/org/traccar/protocol/GpsGateProtocolDecoder.java
+++ b/src/org/traccar/protocol/GpsGateProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2013 - 2015 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,13 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.helper.Checksum;
+import org.traccar.helper.DateBuilder;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
import org.traccar.model.Position;
public class GpsGateProtocolDecoder extends BaseProtocolDecoder {
@@ -31,18 +31,19 @@ public class GpsGateProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "\\$GPRMC," +
- "(\\d{2})(\\d{2})(\\d{2})\\.?(?:\\d+)?," + // Time (HHMMSS.SSS)
- "([AV])," + // Validity
- "(\\d{2})(\\d{2}\\.\\d+)," + // Latitude (DDMM.MMMM)
- "([NS])," +
- "(\\d{3})(\\d{2}\\.\\d+)," + // Longitude (DDDMM.MMMM)
- "([EW])," +
- "(\\d+\\.\\d+)?," + // Speed
- "(\\d+\\.\\d+)?," + // Course
- "(\\d{2})(\\d{2})(\\d{2})" + // Date (DDMMYY)
- ".+"); // Other (Checksumm)
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("$GPRMC,")
+ .number("(dd)(dd)(dd).?(d+)?,") // time
+ .expression("([AV]),") // validity
+ .number("(dd)(dd.d+),") // latitude
+ .expression("([NS]),")
+ .number("(ddd)(dd.d+),") // longitude
+ .expression("([EW]),")
+ .number("(d+.d+)?,") // speed
+ .number("(d+.d+)?,") // course
+ .number("(dd)(dd)(dd)") // date (ddmmyy)
+ .any()
+ .compile();
private void send(Channel channel, String message) {
if (channel != null) {
@@ -52,8 +53,7 @@ public class GpsGateProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
@@ -87,58 +87,26 @@ public class GpsGateProtocolDecoder extends BaseProtocolDecoder {
} else if (sentence.startsWith("$GPRMC,") && hasDeviceId()) {
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
- Integer index = 1;
-
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
-
- // Validity
- position.setValid(parser.group(index++).compareTo("A") == 0);
-
- // Latitude
- Double latitude = Double.parseDouble(parser.group(index++));
- latitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("S") == 0) latitude = -latitude;
- position.setLatitude(latitude);
-
- // Longitude
- Double longitude = Double.parseDouble(parser.group(index++));
- longitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("W") == 0) longitude = -longitude;
- position.setLongitude(longitude);
-
- // Speed
- String speed = parser.group(index++);
- if (speed != null) {
- position.setSpeed(Double.parseDouble(speed));
- }
+ DateBuilder dateBuilder = new DateBuilder()
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt());
- // Course
- String course = parser.group(index++);
- if (course != null) {
- position.setCourse(Double.parseDouble(course));
- }
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
- // Date
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
+ dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
return position;
}
diff --git a/src/org/traccar/protocol/GpsMarkerProtocolDecoder.java b/src/org/traccar/protocol/GpsMarkerProtocolDecoder.java
index c9d9b0cce..9313ad099 100644
--- a/src/org/traccar/protocol/GpsMarkerProtocolDecoder.java
+++ b/src/org/traccar/protocol/GpsMarkerProtocolDecoder.java
@@ -16,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
@@ -31,99 +31,60 @@ public class GpsMarkerProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "\\$GM" +
- "\\d" + // Type
- "(?:\\p{XDigit}{2})?" + // Index
- "(\\d{15})" + // IMEI
- "T(\\d{2})(\\d{2})(\\d{2})" + // Date
- "(\\d{2})(\\d{2})(\\d{2})?" + // Time
- "([NS])" +
- "(\\d{2})(\\d{2}\\d{4})" + // Latitude
- "([EW])" +
- "(\\d{3})(\\d{2}\\d{4})" + // Longitude
- "(\\d{3})" + // Speed
- "(\\d{3})" + // Course
- "(\\d)" + // Satellites
- "(\\d{2})" + // Battery
- "(\\d)" + // Input
- "(\\d)" + // Output
- "(\\d{3})" + // Temperature
- ".*");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("$GM")
+ .number("d") // type
+ .number("(?:xx)?") // index
+ .number("(d{15})") // imei
+ .number("T(dd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd)?") // time
+ .expression("([NS])")
+ .number("(dd)(dd)(dddd)") // latitude
+ .expression("([EW])")
+ .number("(ddd)(dd)(dddd)") // longitude
+ .number("(ddd)") // speed
+ .number("(ddd)") // course
+ .number("(d)") // satellites
+ .number("(dd)") // battery
+ .number("(d)") // input
+ .number("(d)") // output
+ .number("(ddd)") // temperature
+ .any()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String sentence = (String) msg;
-
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
-
- // Get device by IMEI
- String imei = parser.group(index++);
- if (!identify(imei, channel, remoteAddress)) {
+ if (!identify(parser.next(), channel, remoteAddress)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Date and Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- String seconds = parser.group(index++);
- if (seconds != null) {
- time.set(Calendar.SECOND, Integer.parseInt(seconds));
- }
- position.setTime(time.getTime());
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Validity
position.setValid(true);
-
- // Latitude
- String hemisphere = parser.group(index++);
- Double latitude = Double.parseDouble(parser.group(index++));
- latitude += Double.parseDouble(parser.group(index++)) / 600000;
- if (hemisphere.compareTo("S") == 0) {
- latitude = -latitude;
- }
- position.setLatitude(latitude);
-
- // Longitude
- hemisphere = parser.group(index++);
- Double longitude = Double.parseDouble(parser.group(index++));
- longitude += Double.parseDouble(parser.group(index++)) / 600000;
- if (hemisphere.compareTo("W") == 0) {
- longitude = -longitude;
- }
- position.setLongitude(longitude);
-
- // Speed
- position.setSpeed(Double.parseDouble(parser.group(index++)));
-
- // Course
- position.setCourse(Double.parseDouble(parser.group(index++)));
-
- // Additional data
- position.set(Event.KEY_SATELLITES, parser.group(index++));
- position.set(Event.KEY_BATTERY, parser.group(index++));
- position.set(Event.KEY_INPUT, parser.group(index++));
- position.set(Event.KEY_OUTPUT, parser.group(index++));
- position.set(Event.PREFIX_TEMP + 1, parser.group(index++));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN));
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
+
+ position.set(Event.KEY_SATELLITES, parser.next());
+ position.set(Event.KEY_BATTERY, parser.next());
+ position.set(Event.KEY_INPUT, parser.next());
+ position.set(Event.KEY_OUTPUT, parser.next());
+ position.set(Event.PREFIX_TEMP + 1, parser.next());
return position;
}
diff --git a/src/org/traccar/protocol/GpsmtaProtocolDecoder.java b/src/org/traccar/protocol/GpsmtaProtocolDecoder.java
index 37023181e..0ee207219 100644
--- a/src/org/traccar/protocol/GpsmtaProtocolDecoder.java
+++ b/src/org/traccar/protocol/GpsmtaProtocolDecoder.java
@@ -32,7 +32,7 @@ public class GpsmtaProtocolDecoder extends BaseProtocolDecoder {
}
private static final Pattern PATTERN = new PatternBuilder()
- .number("(d+) ") // uid
+ .expression("([^ ]+) ") // uid
.number("(d+) ") // time
.number("(d+.d+) ") // latitude
.number("(d+.d+) ") // longitude
diff --git a/src/org/traccar/protocol/Gt02ProtocolDecoder.java b/src/org/traccar/protocol/Gt02ProtocolDecoder.java
index 76756f41d..81a04be0a 100644
--- a/src/org/traccar/protocol/Gt02ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gt02ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2012 - 2015 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,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
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;
@@ -49,8 +49,7 @@ public class Gt02ProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -74,50 +73,40 @@ public class Gt02ProtocolDecoder extends BaseProtocolDecoder {
} else if (type == MSG_DATA) {
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
position.set(Event.KEY_INDEX, index);
- // Get device id
if (!identify(imei, channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Date and time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000 + buf.readUnsignedByte());
- time.set(Calendar.MONTH, buf.readUnsignedByte() - 1);
- time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte());
- time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte());
- time.set(Calendar.MINUTE, buf.readUnsignedByte());
- time.set(Calendar.SECOND, buf.readUnsignedByte());
- position.setTime(time.getTime());
-
- // Latitude
- double latitude = buf.readUnsignedInt() / (60.0 * 30000.0);
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ position.setTime(dateBuilder.getDate());
- // Longitude
+ double latitude = buf.readUnsignedInt() / (60.0 * 30000.0);
double longitude = buf.readUnsignedInt() / (60.0 * 30000.0);
- // Speed
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
-
- // Course
position.setCourse(buf.readUnsignedShort());
buf.skipBytes(3); // reserved
- // Flags
long flags = buf.readUnsignedInt();
- position.setValid((flags & 0x1) == 0x1);
- if ((flags & 0x2) == 0) latitude = -latitude;
- if ((flags & 0x4) == 0) longitude = -longitude;
+ position.setValid(BitUtil.check(flags, 0));
+ if (!BitUtil.check(flags, 1)) {
+ latitude = -latitude;
+ }
+ if (!BitUtil.check(flags, 2)) {
+ longitude = -longitude;
+ }
position.setLatitude(latitude);
position.setLongitude(longitude);
+
return position;
}
diff --git a/src/org/traccar/protocol/H02ProtocolDecoder.java b/src/org/traccar/protocol/H02ProtocolDecoder.java
index 4cb197c3d..d245fbdc8 100644
--- a/src/org/traccar/protocol/H02ProtocolDecoder.java
+++ b/src/org/traccar/protocol/H02ProtocolDecoder.java
@@ -170,8 +170,7 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
String marker = buf.toString(0, 1, Charset.defaultCharset());
diff --git a/src/org/traccar/protocol/HaicomProtocolDecoder.java b/src/org/traccar/protocol/HaicomProtocolDecoder.java
index 42d806728..db6090650 100644
--- a/src/org/traccar/protocol/HaicomProtocolDecoder.java
+++ b/src/org/traccar/protocol/HaicomProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2014 - 2015 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,12 +16,13 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
+import org.traccar.helper.BitUtil;
+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;
@@ -31,93 +32,78 @@ public class HaicomProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "\\$GPRS" +
- "(\\d+)," + // IMEI
- "([^,]+)," + // Version
- "(\\d{2})(\\d{2})(\\d{2})," + // Date
- "(\\d{2})(\\d{2})(\\d{2})," + // Time
- "(\\d)" + // Flags
- "(\\d{2})(\\d{5})" + // Latitude (DDMMMMM)
- "(\\d{3})(\\d{5})," + // Longitude (DDDMMMMM)
- "(\\d+)," + // Speed
- "(\\d+)," + // Course
- "(\\d+)," + // Status
- "(\\d+)?," + // GPRS counting value
- "(\\d+)?," + // GPS power saving counting value
- "(\\d+)," + // Switch status
- "(\\d+)" + // Relay status
- "(?:[LH]{2})?" + // Power status
- "#V(\\d+).*"); // Battery
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("$GPRS")
+ .number("(d+),") // imei
+ .expression("([^,]+),") // version
+ .number("(dd)(dd)(dd),") // date
+ .number("(dd)(dd)(dd),") // time
+ .number("(d)") // flags
+ .number("(dd)(d{5})") // latitude
+ .number("(ddd)(d{5}),") // longitude
+ .number("(d+),") // speed
+ .number("(d+),") // course
+ .number("(d+),") // status
+ .number("(d+)?,") // gprs counting value
+ .number("(d+)?,") // gps power saving counting value
+ .number("(d+),") // switch status
+ .number("(d+)") // relay status
+ .expression("(?:[LH]{2})?") // power status
+ .number("#V(d+)") // battery
+ .any()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String sentence = (String) msg;
-
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
-
- // Get device by IMEI
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Firmware version
- position.set(Event.KEY_VERSION, parser.group(index++));
-
- // Date
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
-
- // Validity
- int flags = Integer.parseInt(parser.group(index++));
- position.setValid((flags & 0x1) != 0);
-
- // Latitude
- Double latitude = Double.parseDouble(parser.group(index++));
- latitude += Double.parseDouble(parser.group(index++)) / 60000;
- if ((flags & 0x4) == 0) latitude = -latitude;
- position.setLatitude(latitude);
-
- // Longitude
- Double longitude = Double.parseDouble(parser.group(index++));
- longitude += Double.parseDouble(parser.group(index++)) / 60000;
- if ((flags & 0x2) == 0) longitude = -longitude;
- position.setLongitude(longitude);
-
- // Speed
- position.setSpeed(Double.parseDouble(parser.group(index++)) / 10);
-
- // Course
- position.setCourse(Double.parseDouble(parser.group(index++)) / 10);
-
- // Additional data
- position.set(Event.KEY_STATUS, parser.group(index++));
- position.set(Event.KEY_GSM, parser.group(index++));
- position.set(Event.KEY_GPS, parser.group(index++));
- position.set(Event.KEY_INPUT, parser.group(index++));
- position.set(Event.KEY_OUTPUT, parser.group(index++));
- position.set(Event.KEY_BATTERY, Double.parseDouble(parser.group(index++)) / 10);
+ position.set(Event.KEY_VERSION, parser.next());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+
+ int flags = parser.nextInt();
+
+ position.setValid(BitUtil.check(flags, 0));
+
+ double latitude = parser.nextDouble() + parser.nextDouble() / 60000;
+ if (BitUtil.check(flags, 2)) {
+ position.setLatitude(latitude);
+ } else {
+ position.setLatitude(-latitude);
+ }
+
+ double longitude = parser.nextDouble() + parser.nextDouble() / 60000;
+ if (BitUtil.check(flags, 1)) {
+ position.setLongitude(longitude);
+ } else {
+ position.setLongitude(-longitude);
+ }
+
+ position.setSpeed(parser.nextDouble() / 10);
+ position.setCourse(parser.nextDouble() / 10);
+
+ position.set(Event.KEY_STATUS, parser.next());
+ position.set(Event.KEY_GSM, parser.next());
+ position.set(Event.KEY_GPS, parser.next());
+ position.set(Event.KEY_INPUT, parser.next());
+ position.set(Event.KEY_OUTPUT, parser.next());
+ position.set(Event.KEY_BATTERY, parser.nextDouble() / 10);
return position;
}
diff --git a/src/org/traccar/protocol/HuabaoFrameDecoder.java b/src/org/traccar/protocol/HuabaoFrameDecoder.java
new file mode 100644
index 000000000..003876fe5
--- /dev/null
+++ b/src/org/traccar/protocol/HuabaoFrameDecoder.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 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.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.frame.FrameDecoder;
+
+public class HuabaoFrameDecoder extends FrameDecoder {
+
+ @Override
+ protected Object decode(
+ ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception {
+
+ if (buf.readableBytes() < 2) {
+ return null;
+ }
+
+ int index = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) 0x7e);
+ if (index != -1) {
+ ChannelBuffer result = ChannelBuffers.buffer(index + 1 - buf.readerIndex());
+
+ while (buf.readerIndex() <= index) {
+ int b = buf.readUnsignedByte();
+ if (b == 0x7d) {
+ int ext = buf.readUnsignedByte();
+ if (ext == 0x01) {
+ result.writeByte(0x7d);
+ } else if (ext == 0x02) {
+ result.writeByte(0x7e);
+ }
+ } else {
+ result.writeByte(b);
+ }
+ }
+
+ return result;
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/protocol/HuabaoProtocol.java b/src/org/traccar/protocol/HuabaoProtocol.java
new file mode 100644
index 000000000..9f41bb8c6
--- /dev/null
+++ b/src/org/traccar/protocol/HuabaoProtocol.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 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.traccar.BaseProtocol;
+import org.traccar.TrackerServer;
+
+import java.util.List;
+
+public class HuabaoProtocol extends BaseProtocol {
+
+ public HuabaoProtocol() {
+ super("huabao");
+ }
+
+ @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 HuabaoFrameDecoder());
+ pipeline.addLast("objectDecoder", new HuabaoProtocolDecoder(HuabaoProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/org/traccar/protocol/HuabaoProtocolDecoder.java
new file mode 100644
index 000000000..931f985a5
--- /dev/null
+++ b/src/org/traccar/protocol/HuabaoProtocolDecoder.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 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.traccar.BaseProtocolDecoder;
+
+import java.net.SocketAddress;
+
+public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
+
+ public HuabaoProtocolDecoder(HuabaoProtocol protocol) {
+ super(protocol);
+ }
+
+ public static final int MSG_TERMINAL_REGISTER = 0x0100;
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ChannelBuffer buf = (ChannelBuffer) msg;
+
+ buf.readUnsignedByte(); // start marker
+ //int type = buf.readUnsignedShort();
+ //int flags = buf.readUnsignedShort();
+ buf.skipBytes(6); // phone number
+ buf.readUnsignedShort(); // index
+
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/protocol/IntellitracProtocolDecoder.java b/src/org/traccar/protocol/IntellitracProtocolDecoder.java
index 6c5c0f58a..20a0f9160 100644
--- a/src/org/traccar/protocol/IntellitracProtocolDecoder.java
+++ b/src/org/traccar/protocol/IntellitracProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2013 - 2015 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,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
@@ -31,105 +31,88 @@ public class IntellitracProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "(?:.+,)?(\\d+)," + // Device Identifier
- "(\\d{4})(\\d{2})(\\d{2})" + // Date (YYYYMMDD)
- "(\\d{2})(\\d{2})(\\d{2})," + // Time (HHMMSS)
- "(-?\\d+\\.\\d+)," + // Longitude
- "(-?\\d+\\.\\d+)," + // Latitude
- "(\\d+\\.?\\d*)," + // Speed
- "(\\d+\\.?\\d*)," + // Course
- "(-?\\d+\\.?\\d*)," + // Altitude
- "(\\d+)," + // Satellites
- "(\\d+)," + // Report Identifier
- "(\\d+)," + // Input
- "(\\d+),?" + // Output
- "(\\d+\\.\\d+)?,?" + // ADC1
- "(\\d+\\.\\d+)?,?" + // ADC2
- "(?:\\d{14},\\d+," +
- "(\\d+)," + // VSS
- "(\\d+)," + // RPM
- "(-?\\d+)," + // Coolant
- "(\\d+)," + // Fuel
- "(\\d+)," + // Fuel Consumption
- "(-?\\d+)," + // Fuel Temperature
- "(\\d+)," + // Charger Pressure
- "(\\d+)," + // TPL
- "(\\d+)," + // Axle Weight
- "(\\d+))?" + // Odometer
- ".*");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .expression(".+,").optional()
+ .number("(d+),") // identifier
+ .number("(dddd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd),") // time
+ .number("(-?d+.d+),") // longitude
+ .number("(-?d+.d+),") // latitude
+ .number("(d+.?d*),") // speed
+ .number("(d+.?d*),") // course
+ .number("(-?d+.?d*),") // altitude
+ .number("(d+),") // satellites
+ .number("(d+),") // index
+ .number("(d+),") // input
+ .number("(d+),?") // output
+ .number("(d+.d+)?,?") // adc1
+ .number("(d+.d+)?,?") // adc2
+ .groupBegin()
+ .number("d{14},d+,")
+ .number("(d+),") // vss
+ .number("(d+),") // rpm
+ .number("(-?d+),") // coolant
+ .number("(d+),") // fuel
+ .number("(d+),") // fuel consumption
+ .number("(-?d+),") // fuel temperature
+ .number("(d+),") // charger pressure
+ .number("(d+),") // tpl
+ .number("(d+),") // axle weight
+ .number("(d+)") // odometer
+ .groupEnd("?")
+ .any()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String sentence = (String) msg;
-
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
- // Detect device
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Date and time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
-
- // Location data
- position.setLongitude(Double.parseDouble(parser.group(index++)));
- position.setLatitude(Double.parseDouble(parser.group(index++)));
- position.setSpeed(Double.parseDouble(parser.group(index++)));
- position.setCourse(Double.parseDouble(parser.group(index++)));
- position.setAltitude(Double.parseDouble(parser.group(index++)));
-
- // Satellites
- int satellites = Integer.parseInt(parser.group(index++));
- position.setValid(satellites >= 3);
- position.set(Event.KEY_SATELLITES, satellites);
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Report identifier
- position.set(Event.KEY_INDEX, Long.parseLong(parser.group(index++)));
+ position.setLongitude(parser.nextDouble());
+ position.setLatitude(parser.nextDouble());
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
+ position.setAltitude(parser.nextDouble());
- // Input
- position.set(Event.KEY_INPUT, parser.group(index++));
+ int satellites = parser.nextInt();
+ position.setValid(satellites >= 3);
+ position.set(Event.KEY_SATELLITES, satellites);
- // Output
- position.set(Event.KEY_OUTPUT, parser.group(index++));
+ position.set(Event.KEY_INDEX, parser.nextLong());
+ position.set(Event.KEY_INPUT, parser.next());
+ position.set(Event.KEY_OUTPUT, parser.next());
- // ADC
- position.set(Event.PREFIX_ADC + 1, parser.group(index++));
- position.set(Event.PREFIX_ADC + 2, parser.group(index++));
+ position.set(Event.PREFIX_ADC + 1, parser.next());
+ position.set(Event.PREFIX_ADC + 2, parser.next());
// J1939 data
- position.set(Event.KEY_OBD_SPEED, parser.group(index++));
- position.set(Event.KEY_RPM, parser.group(index++));
- position.set("coolant", parser.group(index++));
- position.set(Event.KEY_FUEL, parser.group(index++));
- position.set("consumption", parser.group(index++));
- position.set(Event.PREFIX_TEMP + 1, parser.group(index++));
- position.set(Event.KEY_CHARGE, parser.group(index++));
- position.set("tpl", parser.group(index++));
- position.set("axle", parser.group(index++));
- position.set(Event.KEY_ODOMETER, parser.group(index++));
+ position.set(Event.KEY_OBD_SPEED, parser.next());
+ position.set(Event.KEY_RPM, parser.next());
+ position.set("coolant", parser.next());
+ position.set(Event.KEY_FUEL, parser.next());
+ position.set("consumption", parser.next());
+ position.set(Event.PREFIX_TEMP + 1, parser.next());
+ position.set(Event.KEY_CHARGE, parser.next());
+ position.set("tpl", parser.next());
+ position.set("axle", parser.next());
+ position.set(Event.KEY_ODOMETER, parser.next());
return position;
}
diff --git a/src/org/traccar/protocol/Jt600ProtocolDecoder.java b/src/org/traccar/protocol/Jt600ProtocolDecoder.java
index ae74a1e83..116625ee9 100644
--- a/src/org/traccar/protocol/Jt600ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Jt600ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2013 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2012 - 2015 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,15 +17,16 @@ package org.traccar.protocol;
import java.net.SocketAddress;
import java.nio.charset.Charset;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.ChannelBufferTools;
+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;
@@ -48,58 +49,49 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
buf.readByte(); // header
- // Get device by identifier
String id = String.valueOf(Long.parseLong(ChannelBuffers.hexDump(buf.readBytes(5))));
if (!identify(id, channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Protocol and type
int version = ChannelBufferTools.readHexInteger(buf, 1);
buf.readUnsignedByte(); // type
-
buf.readBytes(2); // length
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.DAY_OF_MONTH, ChannelBufferTools.readHexInteger(buf, 2));
- time.set(Calendar.MONTH, ChannelBufferTools.readHexInteger(buf, 2) - 1);
- time.set(Calendar.YEAR, 2000 + ChannelBufferTools.readHexInteger(buf, 2));
- time.set(Calendar.HOUR_OF_DAY, ChannelBufferTools.readHexInteger(buf, 2));
- time.set(Calendar.MINUTE, ChannelBufferTools.readHexInteger(buf, 2));
- time.set(Calendar.SECOND, ChannelBufferTools.readHexInteger(buf, 2));
- position.setTime(time.getTime());
-
- // Coordinates
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDay(ChannelBufferTools.readHexInteger(buf, 2))
+ .setMonth(ChannelBufferTools.readHexInteger(buf, 2))
+ .setYear(ChannelBufferTools.readHexInteger(buf, 2))
+ .setHour(ChannelBufferTools.readHexInteger(buf, 2))
+ .setMinute(ChannelBufferTools.readHexInteger(buf, 2))
+ .setSecond(ChannelBufferTools.readHexInteger(buf, 2));
+ position.setTime(dateBuilder.getDate());
+
double latitude = convertCoordinate(ChannelBufferTools.readHexInteger(buf, 8));
double longitude = convertCoordinate(ChannelBufferTools.readHexInteger(buf, 9));
- // Flags
byte flags = buf.readByte();
position.setValid((flags & 0x1) == 0x1);
- if ((flags & 0x2) == 0) latitude = -latitude;
+ if ((flags & 0x2) == 0) {
+ latitude = -latitude;
+ }
position.setLatitude(latitude);
- if ((flags & 0x4) == 0) longitude = -longitude;
+ if ((flags & 0x4) == 0) {
+ longitude = -longitude;
+ }
position.setLongitude(longitude);
- // Speed
position.setSpeed(ChannelBufferTools.readHexInteger(buf, 2));
-
- // Course
position.setCourse(buf.readUnsignedByte() * 2.0);
if (version == 1) {
position.set(Event.KEY_SATELLITES, buf.readUnsignedByte());
-
- // Power
position.set(Event.KEY_POWER, buf.readUnsignedByte());
buf.readByte(); // other flags and sensors
- // Altitude
position.setAltitude(buf.readUnsignedShort());
position.set(Event.KEY_CELL, buf.readUnsignedShort());
@@ -117,96 +109,72 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
position.set(Event.KEY_FUEL, fuel);
}
+
return position;
}
- private static final Pattern PATTERN = Pattern.compile(
- "\\(" +
- "([\\d]+)," + // Id
- "W01," + // Type
- "(\\d{3})(\\d{2}.\\d{4})," + // Longitude (DDDMM.MMMM)
- "([EW])," +
- "(\\d{2})(\\d{2}.\\d{4})," + // Latitude (DDMM.MMMM)
- "([NS])," +
- "([AV])," + // Validity
- "(\\d{2})(\\d{2})(\\d{2})," + // Date (DDMMYY)
- "(\\d{2})(\\d{2})(\\d{2})," + // Time (HHMMSS)
- "(\\d+)," + // Speed (km/h)
- "(\\d+)," + // Course
- "(\\d+)," + // Power
- "(\\d+)," + // GPS signal
- "(\\d+)," + // GSM signal
- "(\\d+)," + // Alert Type
- ".*\\)");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("(")
+ .number("(d+),") // id
+ .text("W01,") // type
+ .number("(ddd)(dd.dddd),") // longitude
+ .expression("([EW]),")
+ .number("(dd)(dd.dddd),") // latitude
+ .expression("([NS]),")
+ .expression("([AV]),") // validity
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .number("(dd)(dd)(dd),") // time
+ .number("(d+),") // speed
+ .number("(d+),") // course
+ .number("(d+),") // power
+ .number("(d+),") // gps signal
+ .number("(d+),") // gsm signal
+ .number("(d+),") // alert type
+ .any()
+ .text(")")
+ .compile();
private Position decodeAlertMessage(ChannelBuffer buf, Channel channel) {
- String message = buf.toString(Charset.defaultCharset());
-
- // Parse message
- Matcher parser = PATTERN.matcher(message);
+ Parser parser = new Parser(PATTERN, buf.toString(Charset.defaultCharset()));
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
+
position.set(Event.KEY_ALARM, true);
- Integer index = 1;
- // Get device by identifier
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Longitude
- Double longitude = Double.parseDouble(parser.group(index++));
- longitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("W") == 0) longitude = -longitude;
- position.setLongitude(longitude);
-
- // Latitude
- Double latitude = Double.parseDouble(parser.group(index++));
- latitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("S") == 0) latitude = -latitude;
- position.setLatitude(latitude);
-
- // Validity
- position.setValid(parser.group(index++).compareTo("A") == 0);
+ position.setLongitude(parser.nextCoordinate());
+ position.setLatitude(parser.nextCoordinate());
+ position.setValid(parser.next().equals("A"));
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Speed
- position.setSpeed(Double.parseDouble(parser.group(index++)));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
- // Course
- position.setCourse(Double.parseDouble(parser.group(index++)));
+ position.set(Event.KEY_POWER, parser.nextDouble());
- // Power
- position.set(Event.KEY_POWER, Double.parseDouble(parser.group(index++)));
return position;
}
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
char first = (char) buf.getByte(0);
- // Check message type
if (first == '$') {
return decodeNormalMessage(buf, channel);
} else if (first == '(') {
diff --git a/src/org/traccar/protocol/KhdProtocolDecoder.java b/src/org/traccar/protocol/KhdProtocolDecoder.java
index 1ae192bf5..f6083be70 100644
--- a/src/org/traccar/protocol/KhdProtocolDecoder.java
+++ b/src/org/traccar/protocol/KhdProtocolDecoder.java
@@ -16,14 +16,13 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
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.ChannelBufferTools;
import org.traccar.helper.Checksum;
+import org.traccar.helper.DateBuilder;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -60,8 +59,7 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -72,34 +70,28 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder {
if (type == MSG_ON_DEMAND || type == MSG_POSITION_UPLOAD || type == MSG_POSITION_REUPLOAD
|| type == MSG_ALARM || type == MSG_REPLY || type == MSG_PERIPHERAL) {
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- // Device identification
if (!identify(readSerialNumber(buf), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Date and time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000 + ChannelBufferTools.readHexInteger(buf, 2));
- time.set(Calendar.MONTH, ChannelBufferTools.readHexInteger(buf, 2) - 1);
- time.set(Calendar.DAY_OF_MONTH, ChannelBufferTools.readHexInteger(buf, 2));
- time.set(Calendar.HOUR_OF_DAY, ChannelBufferTools.readHexInteger(buf, 2));
- time.set(Calendar.MINUTE, ChannelBufferTools.readHexInteger(buf, 2));
- time.set(Calendar.SECOND, ChannelBufferTools.readHexInteger(buf, 2));
- position.setTime(time.getTime());
-
- // Location
+ DateBuilder dateBuilder = new DateBuilder()
+ .setYear(ChannelBufferTools.readHexInteger(buf, 2))
+ .setMonth(ChannelBufferTools.readHexInteger(buf, 2))
+ .setDay(ChannelBufferTools.readHexInteger(buf, 2))
+ .setHour(ChannelBufferTools.readHexInteger(buf, 2))
+ .setMinute(ChannelBufferTools.readHexInteger(buf, 2))
+ .setSecond(ChannelBufferTools.readHexInteger(buf, 2));
+ position.setTime(dateBuilder.getDate());
+
position.setLatitude(ChannelBufferTools.readCoordinate(buf));
position.setLongitude(ChannelBufferTools.readCoordinate(buf));
position.setSpeed(UnitsConverter.knotsFromKph(ChannelBufferTools.readHexInteger(buf, 4)));
position.setCourse(ChannelBufferTools.readHexInteger(buf, 4));
- // Flags
int flags = buf.readUnsignedByte();
position.setValid((flags & 0x80) != 0);
@@ -109,14 +101,10 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder {
} else {
- // Odometer
position.set(Event.KEY_ODOMETER, buf.readUnsignedMedium());
- // Status
- buf.skipBytes(4);
-
- // Other
- buf.skipBytes(8);
+ buf.skipBytes(4); // status
+ buf.skipBytes(8); // other
}
diff --git a/src/org/traccar/protocol/M2mProtocolDecoder.java b/src/org/traccar/protocol/M2mProtocolDecoder.java
index 6e57b5766..d60303601 100644
--- a/src/org/traccar/protocol/M2mProtocolDecoder.java
+++ b/src/org/traccar/protocol/M2mProtocolDecoder.java
@@ -16,13 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
+import org.traccar.helper.DateBuilder;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -36,8 +35,7 @@ public class M2mProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -53,7 +51,6 @@ public class M2mProtocolDecoder extends BaseProtocolDecoder {
firstPacket = false;
- // Read IMEI
StringBuilder imei = new StringBuilder();
for (int i = 0; i < 8; i++) {
int b = buf.readByte();
@@ -63,28 +60,23 @@ public class M2mProtocolDecoder extends BaseProtocolDecoder {
imei.append(b % 10);
}
- // Identification
identify(imei.toString(), channel);
} else if (hasDeviceId()) {
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
- // Date and time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte() & 0x3f);
- time.set(Calendar.MONTH, (buf.readUnsignedByte() & 0x3f) - 1);
- time.set(Calendar.YEAR, 2000 + buf.readUnsignedByte());
- time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte() & 0x3f);
- time.set(Calendar.MINUTE, buf.readUnsignedByte() & 0x7f);
- time.set(Calendar.SECOND, buf.readUnsignedByte() & 0x7f);
- position.setTime(time.getTime());
-
- // Location
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDay(buf.readUnsignedByte() & 0x3f)
+ .setMonth(buf.readUnsignedByte() & 0x3f)
+ .setYear(buf.readUnsignedByte())
+ .setHour(buf.readUnsignedByte() & 0x3f)
+ .setMinute(buf.readUnsignedByte() & 0x7f)
+ .setSecond(buf.readUnsignedByte() & 0x7f);
+ position.setTime(dateBuilder.getDate());
+
int degrees = buf.readUnsignedByte();
double latitude = buf.readUnsignedByte();
latitude += buf.readUnsignedByte() / 100.0;
@@ -108,19 +100,19 @@ public class M2mProtocolDecoder extends BaseProtocolDecoder {
latitude = -latitude;
}
+ position.setValid(true);
position.setLatitude(latitude);
position.setLongitude(longitude);
position.setSpeed(buf.readUnsignedByte());
- // Satellites
int satellites = buf.readUnsignedByte();
if (satellites == 0) {
return null; // cell information
}
position.set(Event.KEY_SATELLITES, satellites);
- position.setValid(true);
- // TODO decode everything else
+ // decode other data
+
return position;
}
diff --git a/src/org/traccar/protocol/MaxonProtocolDecoder.java b/src/org/traccar/protocol/MaxonProtocolDecoder.java
deleted file mode 100644
index 14bf285fc..000000000
--- a/src/org/traccar/protocol/MaxonProtocolDecoder.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2012 Alex Wilson <alex@uq.edu.au>
- *
- * 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 java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.jboss.netty.channel.Channel;
-import org.traccar.BaseProtocolDecoder;
-import org.traccar.model.Position;
-
-/**
- * Maxon Datamax GPS send protocol (NMEA + GPFID)
- * As seen in the MA100-1010 router
- *
- * It sends its identity after the GPRMC sentence, and with the type
- * GPFID.
- */
-public class MaxonProtocolDecoder extends BaseProtocolDecoder {
-
- private Position position = null;
-
- public MaxonProtocolDecoder(MaxonProtocol protocol) {
- super(protocol);
- }
-
- private static final Pattern PATTERN = Pattern.compile(
- "\\$GPRMC," +
- "(\\d{2})(\\d{2})(\\d{2})\\.(\\d{2})," + // Time (HHMMSS.SSS)
- "([AV])," + // Validity
- "(\\d{2})(\\d{2}\\.\\d{5})," + // Latitude (DDMM.MMMMM)
- "([NS])," +
- "(\\d{3})(\\d{2}\\.\\d{5})," + // Longitude (DDDMM.MMMMM)
- "([EW])," +
- "(\\d+\\.\\d{3})?," + // Speed
- "(\\d+\\.\\d{2})?," + // Course
- "(\\d{2})(\\d{2})(\\d{2})" + // Date (DDMMYY)
- ".+"); // Other (Checksumm)
-
- private static final Pattern PATTERN_GPFID = Pattern.compile("\\$GPFID,(\\d+)$");
-
- @Override
- protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
-
- String sentence = (String) msg;
-
- // Detect device ID
- // Parse message
- if (sentence.contains("$GPRMC")) {
-
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
- if (!parser.matches()) {
- return null;
- }
-
- // Create new position
- position = new Position();
-
- Integer index = 1;
-
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- index += 1; // Skip milliseconds
-
- // Validity
- position.setValid(parser.group(index++).compareTo("A") == 0);
-
- // Latitude
- Double latitude = Double.parseDouble(parser.group(index++));
- latitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("S") == 0) latitude = -latitude;
- position.setLatitude(latitude);
-
- // Longitude
- Double longitude = Double.parseDouble(parser.group(index++));
- longitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("W") == 0) longitude = -longitude;
- position.setLongitude(longitude);
-
- // Speed
- String speed = parser.group(index++);
- if (speed != null) {
- position.setSpeed(Double.parseDouble(speed));
- }
-
- // Course
- String course = parser.group(index++);
- if (course != null) {
- position.setCourse(Double.parseDouble(course));
- }
-
- // Date
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
-
- } else if (sentence.contains("$GPFID") && position != null) {
- Matcher parser = PATTERN_GPFID.matcher(sentence);
-
- if (parser.matches()) {
- if (!identify(parser.group(1), channel)) {
- return null;
- }
- position.setDeviceId(getDeviceId());
- return position;
- }
- }
-
- return null;
- }
-
-}
diff --git a/src/org/traccar/protocol/MegastekProtocolDecoder.java b/src/org/traccar/protocol/MegastekProtocolDecoder.java
index fd6b2be83..3deff20a8 100644
--- a/src/org/traccar/protocol/MegastekProtocolDecoder.java
+++ b/src/org/traccar/protocol/MegastekProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2013 - 2015 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.
@@ -330,8 +330,7 @@ public class MegastekProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
diff --git a/src/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/org/traccar/protocol/MeitrackProtocolDecoder.java
index 872055f19..86fcac375 100644
--- a/src/org/traccar/protocol/MeitrackProtocolDecoder.java
+++ b/src/org/traccar/protocol/MeitrackProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2012 - 2015 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,16 +17,16 @@ package org.traccar.protocol;
import java.net.SocketAddress;
import java.nio.charset.Charset;
-import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jboss.netty.buffer.ChannelBuffer;
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;
@@ -37,138 +37,117 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "\\$\\$." + // Flag
- "\\d+," + // Length
- "(\\d+)," + // IMEI
- "\\p{XDigit}{3}," + // Command
- "(?:\\d+,)?" +
- "(\\d+)," + // Event
- "(-?\\d+\\.\\d+)," + // Latitude
- "(-?\\d+\\.\\d+)," + // Longitude
- "(\\d{2})(\\d{2})(\\d{2})" + // Date (YYMMDD)
- "(\\d{2})(\\d{2})(\\d{2})," + // Time (HHMMSS)
- "([AV])," + // Validity
- "(\\d+)," + // Satellites
- "(\\d+)," + // GSM Signal
- "(\\d+\\.?\\d*)," + // Speed
- "(\\d+)," + // Course
- "(\\d+\\.?\\d*)," + // HDOP
- "(-?\\d+)," + // Altitude
- "(\\d+)," + // Odometer
- "(\\d+)," + // Runtime
- "(\\d+\\|\\d+\\|\\p{XDigit}+\\|\\p{XDigit}+)," + // Cell
- "(\\p{XDigit}+)," + // State
- "(\\p{XDigit}+)?\\|" + // ADC1
- "(\\p{XDigit}+)?\\|" + // ADC2
- "(\\p{XDigit}+)?\\|" + // ADC3
- "(\\p{XDigit}+)\\|" + // Battery
- "(\\p{XDigit}+)," + // Power
- "(?:([^,]+)?," + // Event Specific
- "[^,]*," + // Reserved
- "\\d*," + // Protocol
- "(\\p{XDigit}{4})?)?" + // Fuel
- ".*\\*\\p{XDigit}{2}(?:\r\n)?");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("$$").expression(".") // flag
+ .number("d+,") // length
+ .number("(d+),") // imei
+ .number("xxx,") // command
+ .number("d+,").optional()
+ .number("(d+),") // event
+ .number("(-?d+.d+),") // latitude
+ .number("(-?d+.d+),") // longitude
+ .number("(dd)(dd)(dd)") // date (ddmmyy)
+ .number("(dd)(dd)(dd),") // time
+ .number("([AV]),") // validity
+ .number("(d+),") // satellites
+ .number("(d+),") // gsm signal
+ .number("(d+.?d*),") // speed
+ .number("(d+),") // course
+ .number("(d+.?d*),") // hdop
+ .number("(-?d+),") // altitude
+ .number("(d+),") // odometer
+ .number("(d+),") // runtime
+ .number("(d+)|") // mcc
+ .number("(d+)|") // mnc
+ .number("(x+)|") // lac
+ .number("(x+),") // cell
+ .number("(x+),") // state
+ .number("(x+)?|") // adc1
+ .number("(x+)?|") // adc2
+ .number("(x+)?|") // adc3
+ .number("(x+)|") // battery
+ .number("(x+),") // power
+ .groupBegin()
+ .expression("([^,]+)?,") // event specific
+ .expression("[^,]*,") // reserved
+ .number("d*,") // protocol
+ .number("(x{4})?") // fuel
+ .groupEnd("?")
+ .any()
+ .text("*")
+ .number("xx")
+ .text("\r\n").optional()
+ .compile();
private Position decodeRegularMessage(Channel channel, ChannelBuffer buf) {
- // Parse message
- String sentence = buf.toString(Charset.defaultCharset());
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, buf.toString(Charset.defaultCharset()));
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
-
- // Identification
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Event
- int event = Integer.parseInt(parser.group(index++));
+ int event = parser.nextInt();
position.set(Event.KEY_EVENT, event);
- // Coordinates
- position.setLatitude(Double.parseDouble(parser.group(index++)));
- position.setLongitude(Double.parseDouble(parser.group(index++)));
-
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
-
- // Validity
- position.setValid(parser.group(index++).compareTo("A") == 0);
+ position.setLatitude(parser.nextDouble());
+ position.setLongitude(parser.nextDouble());
- // Satellites
- position.set(Event.KEY_SATELLITES, parser.group(index++));
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // GSM Signal
- position.set(Event.KEY_GSM, parser.group(index++));
+ position.setValid(parser.next().equals("A"));
- // Speed
- position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(parser.group(index++))));
+ position.set(Event.KEY_SATELLITES, parser.next());
+ position.set(Event.KEY_GSM, parser.next());
- // Course
- position.setCourse(Double.parseDouble(parser.group(index++)));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
- // HDOP
- position.set(Event.KEY_HDOP, parser.group(index++));
+ position.set(Event.KEY_HDOP, parser.next());
- // Altitude
- position.setAltitude(Double.parseDouble(parser.group(index++)));
+ position.setAltitude(parser.nextDouble());
- // Other
- position.set(Event.KEY_ODOMETER, parser.group(index++));
- position.set("runtime", parser.group(index++));
- position.set(Event.KEY_CELL, parser.group(index++));
- position.set(Event.KEY_STATUS, parser.group(index++));
+ position.set(Event.KEY_ODOMETER, parser.next());
+ position.set("runtime", parser.next());
+ position.set(Event.KEY_MCC, parser.next());
+ position.set(Event.KEY_MCC, parser.next());
+ position.set(Event.KEY_LAC, parser.next());
+ position.set(Event.KEY_CELL, parser.next());
+ position.set(Event.KEY_STATUS, parser.next());
- // ADC
- String adc1 = parser.group(index++);
- if (adc1 != null) {
- position.set(Event.PREFIX_ADC + 1, Integer.parseInt(adc1, 16));
- }
- String adc2 = parser.group(index++);
- if (adc2 != null) {
- position.set(Event.PREFIX_ADC + 2, Integer.parseInt(adc2, 16));
- }
- String adc3 = parser.group(index++);
- if (adc3 != null) {
- position.set(Event.PREFIX_ADC + 3, Integer.parseInt(adc3, 16));
+ for (int i = 1; i <= 3; i++) {
+ if (parser.hasNext()) {
+ position.set(Event.PREFIX_ADC + i, parser.nextInt(16));
+ }
}
- position.set(Event.KEY_BATTERY, Integer.parseInt(parser.group(index++), 16));
- position.set(Event.KEY_POWER, Integer.parseInt(parser.group(index++), 16));
- // Event specific
- String data = parser.group(index++);
- if (data != null && !data.isEmpty()) {
+ position.set(Event.KEY_BATTERY, parser.nextInt(16));
+ position.set(Event.KEY_POWER, parser.nextInt(16));
+
+ String eventData = parser.next();
+ if (eventData != null && !eventData.isEmpty()) {
switch (event) {
case 37:
- position.set(Event.KEY_RFID, data);
+ position.set(Event.KEY_RFID, eventData);
break;
default:
- position.set("event-data", data);
+ position.set("event-data", eventData);
break;
}
}
- // Fuel
- String fuel = parser.group(index++);
- if (fuel != null) {
+ if (parser.hasNext()) {
+ String fuel = parser.next();
position.set(Event.KEY_FUEL,
Integer.parseInt(fuel.substring(0, 2), 16) + Integer.parseInt(fuel.substring(2), 16) * 0.01);
}
@@ -182,7 +161,6 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
String flag = buf.toString(2, 1, Charset.defaultCharset());
int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ',');
- // Identification
String imei = buf.toString(index + 1, 15, Charset.defaultCharset());
if (!identify(imei, channel)) {
return null;
@@ -196,64 +174,53 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
- // Event
position.set(Event.KEY_EVENT, buf.readUnsignedByte());
- // Location
position.setLatitude(buf.readInt() * 0.000001);
position.setLongitude(buf.readInt() * 0.000001);
- // Time (946684800 - timestamp for 2000-01-01)
- position.setTime(new Date((946684800 + buf.readUnsignedInt()) * 1000));
+ position.setTime(new Date((946684800 + buf.readUnsignedInt()) * 1000)); // 946684800 = 2000-01-01
- // Validity
position.setValid(buf.readUnsignedByte() == 1);
- // Satellites
position.set(Event.KEY_SATELLITES, buf.readUnsignedByte());
-
- // GSM Signal
position.set(Event.KEY_GSM, buf.readUnsignedByte());
- // Speed
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort()));
-
- // Course
position.setCourse(buf.readUnsignedShort());
- // HDOP
position.set(Event.KEY_HDOP, buf.readUnsignedShort() * 0.1);
- // Altitude
position.setAltitude(buf.readUnsignedShort());
- // Other
position.set(Event.KEY_ODOMETER, buf.readUnsignedInt());
position.set("runtime", buf.readUnsignedInt());
- position.set(Event.KEY_CELL,
- buf.readUnsignedShort() + "|" + buf.readUnsignedShort() + "|" +
- buf.readUnsignedShort() + "|" + buf.readUnsignedShort());
+ position.set(Event.KEY_MCC, buf.readUnsignedShort());
+ position.set(Event.KEY_MCC, buf.readUnsignedShort());
+ position.set(Event.KEY_LAC, buf.readUnsignedShort());
+ position.set(Event.KEY_CELL, buf.readUnsignedShort());
position.set(Event.KEY_STATUS, buf.readUnsignedShort());
- // ADC
position.set(Event.PREFIX_ADC + 1, buf.readUnsignedShort());
position.set(Event.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
position.set(Event.KEY_POWER, buf.readUnsignedShort());
buf.readUnsignedInt(); // geo-fence
+
positions.add(position);
}
- // Delete recorded data
if (channel != null) {
StringBuilder command = new StringBuilder("@@");
command.append(flag).append(27 + positions.size() / 10).append(",");
command.append(imei).append(",CCC,").append(positions.size()).append("*");
int checksum = 0;
- for (int i = 0; i < command.length(); i += 1) checksum += command.charAt(i);
+ for (int i = 0; i < command.length(); i += 1) {
+ checksum += command.charAt(i);
+ }
command.append(String.format("%02x", checksum & 0xff).toUpperCase());
command.append("\r\n");
- channel.write(command.toString());
+ channel.write(command.toString()); // delete processed data
}
return positions;
diff --git a/src/org/traccar/protocol/MiniFinderProtocolDecoder.java b/src/org/traccar/protocol/MiniFinderProtocolDecoder.java
index 0bb9aee60..5a5ef3964 100644
--- a/src/org/traccar/protocol/MiniFinderProtocolDecoder.java
+++ b/src/org/traccar/protocol/MiniFinderProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2014 - 2015 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,12 +16,13 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
+import org.traccar.helper.BitUtil;
+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;
@@ -31,80 +32,76 @@ public class MiniFinderProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "!D," +
- "(\\d+)/(\\d+)/(\\d+)," + // Date
- "(\\d+):(\\d+):(\\d+)," + // Time
- "(-?\\d+\\.\\d+)," + // Latitude
- "(-?\\d+\\.\\d+)," + // Longitude
- "(\\d+\\.?\\d*)," + // Speed
- "(\\d+\\.?\\d*)," + // Course
- "(\\p{XDigit}+)," + // Flags
- "(-?\\d+\\.\\d+)," + // Altitude
- "(\\d+)," + // Battery
- "(\\d+)," + // Satellites in use
- "(\\d+)," + // Satellites in view
- "0");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .expression("![AD],")
+ .number("(d+)/(d+)/(d+),") // date
+ .number("(d+):(d+):(d+),") // time
+ .number("(-?d+.d+),") // latitude
+ .number("(-?d+.d+),") // longitude
+ .number("(d+.?d*),") // speed
+ .number("(d+.?d*),") // course
+ .groupBegin()
+ .number("(x+),") // flags
+ .number("(-?d+.d+),") // altitude
+ .number("(d+),") // battery
+ .number("(d+),") // satellites in use
+ .number("(d+),") // satellites in view
+ .text("0")
+ .or()
+ .any()
+ .groupEnd()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
if (sentence.startsWith("!1")) {
- // Identification
identify(sentence.substring(3, sentence.length()), channel);
- } else if (sentence.startsWith("!D") && hasDeviceId()) {
+ } else if ((sentence.startsWith("!D") || sentence.startsWith("!A")) && hasDeviceId()) {
- // Location
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
- Integer index = 1;
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
+ position.setLatitude(parser.nextDouble());
+ position.setLongitude(parser.nextDouble());
+ position.setSpeed(parser.nextDouble());
- // Location
- position.setLatitude(Double.parseDouble(parser.group(index++)));
- position.setLongitude(Double.parseDouble(parser.group(index++)));
- position.setSpeed(Double.parseDouble(parser.group(index++)));
- position.setCourse(Double.parseDouble(parser.group(index++)));
+ position.setCourse(parser.nextDouble());
+ if (position.getCourse() > 360) {
+ position.setCourse(0);
+ }
+
+ if (parser.hasNext(5)) {
- // Flags
- String flags = parser.group(index++);
- position.set(Event.KEY_FLAGS, flags);
- position.setValid((Integer.parseInt(flags, 16) & 0x01) != 0);
+ int flags = parser.nextInt(16);
+ position.set(Event.KEY_FLAGS, flags);
+ position.setValid(BitUtil.check(flags, 0));
- // Altitude
- position.setAltitude(Double.parseDouble(parser.group(index++)));
+ position.setAltitude(parser.nextDouble());
- // Battery
- position.set(Event.KEY_BATTERY, parser.group(index++));
+ position.set(Event.KEY_BATTERY, parser.next());
+ position.set(Event.KEY_SATELLITES, parser.next());
- // Satellites
- position.set(Event.KEY_SATELLITES, parser.group(index++));
+ }
return position;
+
}
return null;
diff --git a/src/org/traccar/protocol/Mta6ProtocolDecoder.java b/src/org/traccar/protocol/Mta6ProtocolDecoder.java
index c23063e4d..f0349a2ef 100644
--- a/src/org/traccar/protocol/Mta6ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Mta6ProtocolDecoder.java
@@ -17,11 +17,9 @@ package org.traccar.protocol;
import java.net.SocketAddress;
import java.nio.charset.Charset;
-import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
-import java.util.TimeZone;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
@@ -33,6 +31,7 @@ import org.jboss.netty.handler.codec.http.HttpVersion;
import org.traccar.BaseProtocolDecoder;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
+import org.traccar.helper.DateBuilder;
import org.traccar.helper.Log;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -103,14 +102,10 @@ public class Mta6ProtocolDecoder extends BaseProtocolDecoder {
weekNumber = buf.readUnsignedShort();
}
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 1980);
- time.set(Calendar.MONTH, 0);
- time.set(Calendar.DAY_OF_MONTH, 6);
- long offset = time.getTimeInMillis();
+ DateBuilder dateBuilder = new DateBuilder().setDate(1980, 1, 6);
+ dateBuilder.addMillis(weekNumber * 7 * 24 * 60 * 60 * 1000 + weekTime);
- return new Date(offset + weekNumber * 7 * 24 * 60 * 60 * 1000 + weekTime);
+ return dateBuilder.getDate();
}
}
@@ -130,7 +125,6 @@ public class Mta6ProtocolDecoder extends BaseProtocolDecoder {
short flags = buf.readUnsignedByte();
- // Skip events
short event = buf.readUnsignedByte();
if (BitUtil.check(event, 7)) {
if (BitUtil.check(event, 6)) {
@@ -281,13 +275,11 @@ public class Mta6ProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
HttpRequest request = (HttpRequest) msg;
ChannelBuffer buf = request.getContent();
- // Read identifier
buf.skipBytes("id=".length());
int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '&');
String uniqueId = buf.toString(buf.readerIndex(), index - buf.readerIndex(), Charset.defaultCharset());
@@ -297,7 +289,6 @@ public class Mta6ProtocolDecoder extends BaseProtocolDecoder {
buf.skipBytes(uniqueId.length());
buf.skipBytes("&bin=".length());
- // Read header
short packetId = buf.readUnsignedByte();
short offset = buf.readUnsignedByte(); // dataOffset
short packetCount = buf.readUnsignedByte();
@@ -305,13 +296,11 @@ public class Mta6ProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedByte(); // timezone
buf.skipBytes(offset - 5);
- // Send response
if (channel != null) {
sendContinue(channel);
sendResponse(channel, packetId, packetCount);
}
- // Parse data
if (packetId == 0x31 || packetId == 0x32 || packetId == 0x36) {
if (simple) {
return parseFormatA1(buf);
diff --git a/src/org/traccar/protocol/MxtProtocolDecoder.java b/src/org/traccar/protocol/MxtProtocolDecoder.java
index ba97694d3..3ff127d5d 100644
--- a/src/org/traccar/protocol/MxtProtocolDecoder.java
+++ b/src/org/traccar/protocol/MxtProtocolDecoder.java
@@ -16,13 +16,11 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.TimeZone;
import org.jboss.netty.buffer.ChannelBuffer;
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;
@@ -39,8 +37,7 @@ public class MxtProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -64,12 +61,7 @@ public class MxtProtocolDecoder extends BaseProtocolDecoder {
position.set(Event.KEY_INDEX, buf.readUnsignedShort());
- // Date and time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000);
- time.set(Calendar.MONTH, 0);
- time.set(Calendar.DAY_OF_MONTH, 1);
+ DateBuilder dateBuilder = new DateBuilder().setDate(2000, 1, 1);
long date = buf.readUnsignedInt();
@@ -78,12 +70,10 @@ public class MxtProtocolDecoder extends BaseProtocolDecoder {
long minutes = BitUtil.between(date, 6, 6 + 6);
long seconds = BitUtil.to(date, 6);
- long millis = time.getTimeInMillis();
- millis += (((days * 24 + hours) * 60 + minutes) * 60 + seconds) * 1000;
+ dateBuilder.addMillis((((days * 24 + hours) * 60 + minutes) * 60 + seconds) * 1000);
- position.setTime(new Date(millis));
+ position.setTime(dateBuilder.getDate());
- // Location
position.setValid(true);
position.setLatitude(buf.readInt() / 1000000.0);
position.setLongitude(buf.readInt() / 1000000.0);
diff --git a/src/org/traccar/protocol/NavigilProtocolDecoder.java b/src/org/traccar/protocol/NavigilProtocolDecoder.java
index 5ce5d08cb..60aaab345 100644
--- a/src/org/traccar/protocol/NavigilProtocolDecoder.java
+++ b/src/org/traccar/protocol/NavigilProtocolDecoder.java
@@ -261,8 +261,7 @@ public class NavigilProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
diff --git a/src/org/traccar/protocol/NavisProtocolDecoder.java b/src/org/traccar/protocol/NavisProtocolDecoder.java
index 0af74d70e..c5dc9fbdc 100644
--- a/src/org/traccar/protocol/NavisProtocolDecoder.java
+++ b/src/org/traccar/protocol/NavisProtocolDecoder.java
@@ -18,14 +18,14 @@ package org.traccar.protocol;
import java.net.SocketAddress;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
-import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
-import java.util.TimeZone;
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.Log;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -59,11 +59,11 @@ public class NavisProtocolDecoder extends BaseProtocolDecoder {
return false;
}
- private static class ParseResult {
+ private static final class ParseResult {
private final long id;
private final Position position;
- public ParseResult(long id, Position position) {
+ private ParseResult(long id, Position position) {
this.id = id;
this.position = position;
}
@@ -83,7 +83,6 @@ public class NavisProtocolDecoder extends BaseProtocolDecoder {
position.setDeviceId(getDeviceId());
- // Format type
int format;
if (buf.getUnsignedByte(buf.readerIndex()) == 0) {
format = buf.readUnsignedShort();
@@ -95,49 +94,29 @@ public class NavisProtocolDecoder extends BaseProtocolDecoder {
long index = buf.readUnsignedInt();
position.set(Event.KEY_INDEX, index);
- // Event type
position.set(Event.KEY_EVENT, buf.readUnsignedShort());
- // Event time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte());
- time.set(Calendar.MINUTE, buf.readUnsignedByte());
- time.set(Calendar.SECOND, buf.readUnsignedByte());
- time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte());
- time.set(Calendar.MONTH, buf.readUnsignedByte());
- time.set(Calendar.YEAR, 2000 + buf.readUnsignedByte());
- position.set("time", time.getTimeInMillis());
-
- // Alarm status
- position.set(Event.KEY_ALARM, buf.readUnsignedByte());
+ buf.skipBytes(6); // event time
- // Modules status
+ position.set(Event.KEY_ALARM, buf.readUnsignedByte());
position.set(Event.KEY_STATUS, buf.readUnsignedByte());
-
- // GSM signal
position.set(Event.KEY_GSM, buf.readUnsignedByte());
- // Output
if (isFormat(format, F10, F20, F30)) {
position.set(Event.KEY_OUTPUT, buf.readUnsignedShort());
} else if (isFormat(format, F40, F50, F51, F52)) {
position.set(Event.KEY_OUTPUT, buf.readUnsignedByte());
}
- // Input
if (isFormat(format, F10, F20, F30, F40)) {
position.set(Event.KEY_INPUT, buf.readUnsignedShort());
} else if (isFormat(format, F50, F51, F52)) {
position.set(Event.KEY_INPUT, buf.readUnsignedByte());
}
- position.set(Event.KEY_POWER, buf.readUnsignedShort() / 1000.0);
-
- // Battery power
+ position.set(Event.KEY_POWER, buf.readUnsignedShort() * 0.001);
position.set(Event.KEY_BATTERY, buf.readUnsignedShort());
- // Temperature
if (isFormat(format, F10, F20, F30)) {
position.set(Event.PREFIX_TEMP + 1, buf.readShort());
}
@@ -147,46 +126,37 @@ public class NavisProtocolDecoder extends BaseProtocolDecoder {
position.set(Event.PREFIX_ADC + 2, buf.readUnsignedShort());
}
+ // Impulse counters
if (isFormat(format, F20, F50, F51, F52)) {
- // Impulse counters
buf.readUnsignedInt();
buf.readUnsignedInt();
}
if (isFormat(format, F20, F50, F51, F52)) {
- // Validity
int locationStatus = buf.readUnsignedByte();
- position.setValid((locationStatus & 0x02) == 0x02);
-
- // Location time
- time.clear();
- time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte());
- time.set(Calendar.MINUTE, buf.readUnsignedByte());
- time.set(Calendar.SECOND, buf.readUnsignedByte());
- time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte());
- time.set(Calendar.MONTH, buf.readUnsignedByte());
- time.set(Calendar.YEAR, 2000 + buf.readUnsignedByte());
- position.setTime(time.getTime());
-
- // Location data
+ position.setValid(BitUtil.check(locationStatus, 1));
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ position.setTime(dateBuilder.getDate());
+
position.setLatitude(buf.readFloat() / Math.PI * 180);
position.setLongitude(buf.readFloat() / Math.PI * 180);
position.setSpeed(buf.readFloat());
position.setCourse(buf.readUnsignedShort());
- // Odometer
position.set(Event.KEY_ODOMETER, buf.readFloat());
- // Last segment
- position.set("segment", buf.readFloat());
+ position.set("segment", buf.readFloat()); // last segment
// Segment times
buf.readUnsignedShort();
buf.readUnsignedShort();
}
+ // Other
if (isFormat(format, F51, F52)) {
- // Other stuff
buf.readUnsignedShort();
buf.readByte();
buf.readUnsignedShort();
@@ -198,8 +168,8 @@ public class NavisProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedShort();
}
+ // Four temperature sensors
if (isFormat(format, F40, F52)) {
- // Four temperature sensors
buf.readByte();
buf.readByte();
buf.readByte();
@@ -217,7 +187,6 @@ public class NavisProtocolDecoder extends BaseProtocolDecoder {
response.writeInt((int) result.getId());
sendReply(channel, response);
- // No location data
if (result.getPosition().getFixTime() == null) {
return null;
}
@@ -241,7 +210,6 @@ public class NavisProtocolDecoder extends BaseProtocolDecoder {
response.writeByte(count);
sendReply(channel, response);
- // No location data
if (positions.isEmpty()) {
return null;
}
@@ -281,12 +249,10 @@ public class NavisProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
- // Read header
prefix = buf.toString(buf.readerIndex(), 4, CHARSET);
buf.skipBytes(prefix.length()); // prefix @NTC by default
serverId = buf.readUnsignedInt();
@@ -298,7 +264,6 @@ public class NavisProtocolDecoder extends BaseProtocolDecoder {
return null; // keep alive message
}
- // Read message type
String type = buf.toString(buf.readerIndex(), 3, CHARSET);
buf.skipBytes(type.length());
diff --git a/src/org/traccar/protocol/NoranProtocolDecoder.java b/src/org/traccar/protocol/NoranProtocolDecoder.java
index 11408b1ed..35924c5b2 100644
--- a/src/org/traccar/protocol/NoranProtocolDecoder.java
+++ b/src/org/traccar/protocol/NoranProtocolDecoder.java
@@ -20,12 +20,12 @@ import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.TimeZone;
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.model.Event;
import org.traccar.model.Position;
@@ -87,14 +87,10 @@ public class NoranProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedInt(); // GIS port
}
- // Flags
- int flags = buf.readUnsignedByte();
- position.setValid((flags & 0x01) != 0);
+ position.setValid(BitUtil.check(buf.readUnsignedByte(), 0));
- // Alarm type
position.set(Event.KEY_ALARM, buf.readUnsignedByte());
- // Location
if (newFormat) {
position.setSpeed(buf.readUnsignedInt());
position.setCourse(buf.readFloat());
@@ -105,21 +101,18 @@ public class NoranProtocolDecoder extends BaseProtocolDecoder {
position.setLongitude(buf.readFloat());
position.setLatitude(buf.readFloat());
- // Time
if (!newFormat) {
long timeValue = buf.readUnsignedInt();
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000 + (int) (timeValue >> 26));
- time.set(Calendar.MONTH, (int) (timeValue >> 22 & 0x0f) - 1);
- time.set(Calendar.DAY_OF_MONTH, (int) (timeValue >> 17 & 0x1f));
- time.set(Calendar.HOUR_OF_DAY, (int) (timeValue >> 12 & 0x1f));
- time.set(Calendar.MINUTE, (int) (timeValue >> 6 & 0x3f));
- time.set(Calendar.SECOND, (int) (timeValue & 0x3f));
- position.setTime(time.getTime());
+ DateBuilder dateBuilder = new DateBuilder()
+ .setYear((int) BitUtil.from(timeValue, 26))
+ .setMonth((int) BitUtil.between(timeValue, 22, 26))
+ .setDay((int) BitUtil.between(timeValue, 17, 22))
+ .setHour((int) BitUtil.between(timeValue, 12, 17))
+ .setMinute((int) BitUtil.between(timeValue, 6, 12))
+ .setSecond((int) BitUtil.to(timeValue, 6));
+ position.setTime(dateBuilder.getDate());
}
- // Identification
ChannelBuffer rawId;
if (newFormat) {
rawId = buf.readBytes(12);
@@ -132,14 +125,12 @@ public class NoranProtocolDecoder extends BaseProtocolDecoder {
}
position.setDeviceId(getDeviceId());
- // Time
if (newFormat) {
DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
position.setTime(dateFormat.parse(buf.readBytes(17).toString(Charset.defaultCharset())));
buf.readByte();
}
- // Other data
if (!newFormat) {
position.set(Event.PREFIX_IO + 1, buf.readUnsignedByte());
position.set(Event.KEY_FUEL, buf.readUnsignedByte());
diff --git a/src/org/traccar/protocol/OrionProtocolDecoder.java b/src/org/traccar/protocol/OrionProtocolDecoder.java
index b2e1699c3..a208d83e4 100644
--- a/src/org/traccar/protocol/OrionProtocolDecoder.java
+++ b/src/org/traccar/protocol/OrionProtocolDecoder.java
@@ -16,16 +16,13 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
-import java.util.TimeZone;
-
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.DateBuilder;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -56,8 +53,7 @@ public class OrionProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
@@ -80,7 +76,6 @@ public class OrionProtocolDecoder extends BaseProtocolDecoder {
for (int i = 0; i < (header & 0x0f); i++) {
- // Create new position
Position position = new Position();
position.setDeviceId(getDeviceId());
position.setProtocol(getProtocolName());
@@ -89,28 +84,21 @@ public class OrionProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedByte(); // length
position.set(Event.KEY_FLAGS, buf.readUnsignedShort());
- // Location
position.setLatitude(convertCoordinate(buf.readInt()));
position.setLongitude(convertCoordinate(buf.readInt()));
position.setAltitude(buf.readShort() / 10.0);
position.setCourse(buf.readUnsignedShort());
position.setSpeed(buf.readUnsignedShort() * 0.0539957);
- // Date and time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000 + buf.readUnsignedByte());
- time.set(Calendar.MONTH, buf.readUnsignedByte() - 1);
- time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte());
- time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte());
- time.set(Calendar.MINUTE, buf.readUnsignedByte());
- time.set(Calendar.SECOND, buf.readUnsignedByte());
- position.setTime(time.getTime());
-
- // Accuracy
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ position.setTime(dateBuilder.getDate());
+
int satellites = buf.readUnsignedByte();
- position.set(Event.KEY_SATELLITES, satellites);
position.setValid(satellites >= 3);
+ position.set(Event.KEY_SATELLITES, satellites);
+
positions.add(position);
}
diff --git a/src/org/traccar/protocol/OsmAndProtocolDecoder.java b/src/org/traccar/protocol/OsmAndProtocolDecoder.java
index f128c6414..529a2940e 100644
--- a/src/org/traccar/protocol/OsmAndProtocolDecoder.java
+++ b/src/org/traccar/protocol/OsmAndProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2013 - 2015 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.
@@ -42,8 +42,7 @@ public class OsmAndProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
HttpRequest request = (HttpRequest) msg;
QueryStringDecoder decoder = new QueryStringDecoder(request.getUri());
@@ -54,11 +53,9 @@ public class OsmAndProtocolDecoder extends BaseProtocolDecoder {
params = decoder.getParameters();
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- // Identification
String id;
if (params.containsKey("id")) {
id = params.get("id").get(0);
@@ -70,7 +67,6 @@ public class OsmAndProtocolDecoder extends BaseProtocolDecoder {
}
position.setDeviceId(getDeviceId());
- // Decode position
position.setValid(true);
if (params.containsKey("timestamp")) {
try {
@@ -89,7 +85,6 @@ public class OsmAndProtocolDecoder extends BaseProtocolDecoder {
position.setLatitude(Double.parseDouble(params.get("lat").get(0)));
position.setLongitude(Double.parseDouble(params.get("lon").get(0)));
- // Optional parameters
if (params.containsKey("speed")) {
position.setSpeed(Double.parseDouble(params.get("speed").get(0)));
}
@@ -124,7 +119,6 @@ public class OsmAndProtocolDecoder extends BaseProtocolDecoder {
position.set("description", params.get("desc").get(0));
}
- // Send response
if (channel != null) {
HttpResponse response = new DefaultHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
diff --git a/src/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/org/traccar/protocol/PiligrimProtocolDecoder.java
index a1808a3d8..4f194605d 100644
--- a/src/org/traccar/protocol/PiligrimProtocolDecoder.java
+++ b/src/org/traccar/protocol/PiligrimProtocolDecoder.java
@@ -32,6 +32,7 @@ import org.jboss.netty.handler.codec.http.HttpVersion;
import org.jboss.netty.handler.codec.http.QueryStringDecoder;
import org.traccar.BaseProtocolDecoder;
+import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -58,8 +59,7 @@ public class PiligrimProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
HttpRequest request = (HttpRequest) msg;
String uri = request.getUri();
@@ -80,7 +80,6 @@ public class PiligrimProtocolDecoder extends BaseProtocolDecoder {
sendResponse(channel, "BINGPS: OK");
- // Identification
QueryStringDecoder decoder = new QueryStringDecoder(request.getUri());
if (!identify(decoder.getParameters().get("imei").get(0), channel)) {
return null;
@@ -118,47 +117,39 @@ public class PiligrimProtocolDecoder extends BaseProtocolDecoder {
longitude += buf.readUnsignedByte() / 6000.0;
longitude += buf.readUnsignedByte() / 600000.0;
- // Hemisphere
int flags = buf.readUnsignedByte();
- if ((flags & 0x01) != 0) {
+ if (BitUtil.check(flags, 0)) {
latitude = -latitude;
}
- if ((flags & 0x02) != 0) {
+ if (BitUtil.check(flags, 1)) {
longitude = -longitude;
}
position.setLatitude(latitude);
position.setLongitude(longitude);
- // Satellites
int satellites = buf.readUnsignedByte();
position.set(Event.KEY_SATELLITES, satellites);
position.setValid(satellites >= 3);
- // Speed
position.setSpeed(buf.readUnsignedByte());
- // Course
double course = buf.readUnsignedByte() << 1;
course += (flags >> 2) & 1;
course += buf.readUnsignedByte() / 100.0;
position.setCourse(course);
- // Sensors
if (type == MSG_GPS_SENSORS) {
-
- // External power
double power = buf.readUnsignedByte();
power += buf.readUnsignedByte() << 8;
- position.set(Event.KEY_POWER, power / 100);
+ position.set(Event.KEY_POWER, power * 0.01);
- // Battery
double battery = buf.readUnsignedByte();
battery += buf.readUnsignedByte() << 8;
- position.set(Event.KEY_BATTERY, battery / 100);
+ position.set(Event.KEY_BATTERY, battery * 0.01);
buf.skipBytes(6);
-
}
+
positions.add(position);
} else if (type == MSG_EVENTS) {
diff --git a/src/org/traccar/protocol/ProgressProtocolDecoder.java b/src/org/traccar/protocol/ProgressProtocolDecoder.java
index 9fbd601d5..93091e0a1 100644
--- a/src/org/traccar/protocol/ProgressProtocolDecoder.java
+++ b/src/org/traccar/protocol/ProgressProtocolDecoder.java
@@ -18,14 +18,14 @@ package org.traccar.protocol;
import java.net.SocketAddress;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
-import java.util.Calendar;
+import java.util.Date;
import java.util.LinkedList;
import java.util.List;
-import java.util.TimeZone;
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.model.Event;
import org.traccar.model.Position;
@@ -48,8 +48,6 @@ public class ProgressProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_ALARM = 200;
public static final int MSG_ALARM_RECIEVED = 201;
- private static final String HEX_CHARS = "0123456789ABCDEF";
-
private void requestArchive(Channel channel) {
if (lastIndex == 0) {
lastIndex = newIndex;
@@ -64,7 +62,8 @@ public class ProgressProtocolDecoder extends BaseProtocolDecoder {
}
@Override
- protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
int type = buf.readUnsignedShort();
@@ -95,7 +94,6 @@ public class ProgressProtocolDecoder extends BaseProtocolDecoder {
position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
- // Message index
if (type == MSG_LOGMSG) {
position.set(Event.KEY_ARCHIVE, true);
int subtype = buf.readUnsignedShort();
@@ -112,84 +110,47 @@ public class ProgressProtocolDecoder extends BaseProtocolDecoder {
newIndex = buf.readUnsignedInt();
}
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.setTimeInMillis(buf.readUnsignedInt() * 1000);
- position.setTime(time.getTime());
-
- // Latitude
+ position.setTime(new Date(buf.readUnsignedInt() * 1000));
position.setLatitude(buf.readInt() * 180.0 / 0x7FFFFFFF);
-
- // Longitude
position.setLongitude(buf.readInt() * 180.0 / 0x7FFFFFFF);
+ position.setSpeed(buf.readUnsignedInt() * 0.01);
+ position.setCourse(buf.readUnsignedShort() * 0.01);
+ position.setAltitude(buf.readUnsignedShort() * 0.01);
- // Speed
- position.setSpeed(buf.readUnsignedInt() / 100.0);
-
- // Course
- position.setCourse(buf.readUnsignedShort() / 100.0);
-
- // Altitude
- position.setAltitude(buf.readUnsignedShort() / 100.0);
+ int satellites = buf.readUnsignedByte();
+ position.setValid(satellites >= 3);
+ position.set(Event.KEY_SATELLITES, satellites);
- // Satellites
- int satellitesNumber = buf.readUnsignedByte();
- position.set(Event.KEY_SATELLITES, satellitesNumber);
-
- // Validity
- position.setValid(satellitesNumber >= 3);
-
- // Cell signal
position.set(Event.KEY_GSM, buf.readUnsignedByte());
-
- // Odometer
position.set(Event.KEY_ODOMETER, buf.readUnsignedInt());
long extraFlags = buf.readLong();
- // Analog inputs
- if ((extraFlags & 0x1) == 0x1) {
+ if (BitUtil.check(extraFlags, 0)) {
int count = buf.readUnsignedShort();
for (int i = 1; i <= count; i++) {
position.set(Event.PREFIX_ADC + i, buf.readUnsignedShort());
}
}
- // CAN adapter
- if ((extraFlags & 0x2) == 0x2) {
+ if (BitUtil.check(extraFlags, 1)) {
int size = buf.readUnsignedShort();
position.set("can", buf.toString(buf.readerIndex(), size, Charset.defaultCharset()));
buf.skipBytes(size);
}
- // Passenger sensor
- if ((extraFlags & 0x4) == 0x4) {
- int size = buf.readUnsignedShort();
-
- // Convert binary data to hex
- StringBuilder hex = new StringBuilder();
- for (int i = buf.readerIndex(); i < buf.readerIndex() + size; i++) {
- byte b = buf.getByte(i);
- hex.append(HEX_CHARS.charAt((b & 0xf0) >> 4));
- hex.append(HEX_CHARS.charAt(b & 0x0F));
- }
-
- position.set("passenger", hex.toString());
-
- buf.skipBytes(size);
+ if (BitUtil.check(extraFlags, 2)) {
+ position.set("passenger",
+ ChannelBuffers.hexDump(buf.readBytes(buf.readUnsignedShort())));
}
- // Send response for alarm message
if (type == MSG_ALARM) {
+ position.set(Event.KEY_ALARM, true);
byte[] response = {(byte) 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
channel.write(ChannelBuffers.wrappedBuffer(response));
-
- position.set(Event.KEY_ALARM, true);
}
- // Skip CRC
- buf.readUnsignedInt();
+ buf.readUnsignedInt(); // crc
positions.add(position);
}
diff --git a/src/org/traccar/protocol/Pt3000ProtocolDecoder.java b/src/org/traccar/protocol/Pt3000ProtocolDecoder.java
index f2e0a14bc..1eaba20e4 100644
--- a/src/org/traccar/protocol/Pt3000ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Pt3000ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2013 - 2015 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,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.Position;
public class Pt3000ProtocolDecoder extends BaseProtocolDecoder {
@@ -30,84 +30,50 @@ public class Pt3000ProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "%(\\d+)," + // IMEI
- "\\$GPRMC," +
- "(\\d{2})(\\d{2})(\\d{2})\\.?\\d*," + // Time (HHMMSS.SSS)
- "([AV])," + // Validity
- "(\\d{2})(\\d{2}\\.\\d+)," + // Latitude (DDMM.MMMM)
- "([NS])," +
- "(\\d{3})(\\d{2}\\.\\d+)," + // Longitude (DDDMM.MMMM)
- "([EW])," +
- "(\\d+\\.?\\d*)?," + // Speed
- "(\\d+\\.?\\d*)?," + // Course
- "(\\d{2})(\\d{2})(\\d{2})" + // Date (DDMMYY)
- ".+");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .number("%(d+),") // imei
+ .text("$GPRMC,")
+ .number("(dd)(dd)(dd).?d*,") // time
+ .expression("([AV]),") // validity
+ .number("(dd)(dd.d+),") // latitude
+ .expression("([NS]),")
+ .number("(ddd)(dd.d+),") // longitude
+ .expression("([EW]),")
+ .number("(d+.?d*)?,") // speed
+ .number("(d+.?d*)?,") // course
+ .number("(dd)(dd)(dd)") // date (ddmmyy)
+ .any()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String sentence = (String) msg;
-
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
-
- // Identifier
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
-
- // Validity
- position.setValid(parser.group(index++).compareTo("A") == 0);
-
- // Latitude
- Double latitude = Double.parseDouble(parser.group(index++));
- latitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("S") == 0) latitude = -latitude;
- position.setLatitude(latitude);
+ DateBuilder dateBuilder = new DateBuilder()
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
- // Longitude
- Double longitude = Double.parseDouble(parser.group(index++));
- longitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("W") == 0) longitude = -longitude;
- position.setLongitude(longitude);
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
- // Speed
- String speed = parser.group(index++);
- if (speed != null) {
- position.setSpeed(Double.parseDouble(speed));
- }
-
- // Course
- String course = parser.group(index++);
- if (course != null) {
- position.setCourse(Double.parseDouble(course));
- }
+ dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Date
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
return position;
}
diff --git a/src/org/traccar/protocol/Pt502ProtocolDecoder.java b/src/org/traccar/protocol/Pt502ProtocolDecoder.java
index 41336dc05..4eec65758 100644
--- a/src/org/traccar/protocol/Pt502ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Pt502ProtocolDecoder.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2012 - 2014 Anton Tananaev (anton.tananaev@gmail.com)
- * Luis Parada (luis.parada@gmail.com)
+ * Copyright 2012 - 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2012 Luis Parada (luis.parada@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,12 +17,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
@@ -32,120 +32,74 @@ public class Pt502ProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- ".*" +
- "\\$[A-Z]{3}\\d?," + // Type
- "(\\d+)," + // Id
- "(\\d{2})(\\d{2})(\\d{2})\\.(\\d{3})," + // Time (HHMMSS.SSS)
- "([AV])," + // Validity
- "(\\d{2})(\\d{2}\\.\\d{4})," + // Latitude (DDMM.MMMM)
- "([NS])," +
- "(\\d{3})(\\d{2}\\.\\d{4})," + // Longitude (DDDMM.MMMM)
- "([EW])," +
- "(\\d+\\.\\d+)?," + // Speed
- "(\\d+\\.\\d+)?," + // Course
- "(\\d{2})(\\d{2})(\\d{2}),,," + // Date
- "./" +
- "([01])+," + // Input
- "([01])+/" + // Output
- "([^/]+)?/" + // ADC
- "(\\d+)" + // Odometer
- "(?:/([^/]+)?/" + // RFID
- "(\\p{XDigit}{3}))?" + // State
- ".*");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .any().text("$")
+ .expression("[A-Z]{3}")
+ .number("d?,") // type
+ .number("(d+),") // id
+ .number("(dd)(dd)(dd).(ddd),") // time
+ .expression("([AV]),") // validity
+ .number("(dd)(dd.dddd),") // latitude
+ .expression("([NS]),")
+ .number("(ddd)(dd.dddd),") // longitude
+ .expression("([EW]),")
+ .number("(d+.d+)?,") // speed
+ .number("(d+.d+)?,") // course
+ .number("(dd)(dd)(dd),,,") // date
+ .expression("./")
+ .expression("([01])+,") // input
+ .expression("([01])+/") // output
+ .expression("([^/]+)?/") // adc
+ .number("(d+)") // odometer
+ .expression("/([^/]+)?/") // rfid
+ .number("(xxx)").optional(2) // state
+ .any()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String sentence = (String) msg;
-
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
-
- // Get device by IMEI
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MILLISECOND, Integer.parseInt(parser.group(index++)));
-
- // Validity
- position.setValid(parser.group(index++).compareTo("A") == 0);
-
- // Latitude
- Double latitude = Double.parseDouble(parser.group(index++));
- latitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("S") == 0) {
- latitude = -latitude;
- }
- position.setLatitude(latitude);
-
- // Longitude
- Double longitude = Double.parseDouble(parser.group(index++));
- longitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("W") == 0) {
- longitude = -longitude;
- }
- position.setLongitude(longitude);
-
- // Speed
- String speed = parser.group(index++);
- if (speed != null) {
- position.setSpeed(Double.parseDouble(speed));
- }
+ DateBuilder dateBuilder = new DateBuilder()
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt());
- // Course
- String course = parser.group(index++);
- if (course != null) {
- position.setCourse(Double.parseDouble(course));
- }
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
- // Date
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
+ dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // IO
- position.set(Event.KEY_INPUT, parser.group(index++));
- position.set(Event.KEY_OUTPUT, parser.group(index++));
+ position.set(Event.KEY_INPUT, parser.next());
+ position.set(Event.KEY_OUTPUT, parser.next());
- // ADC
- String adc = parser.group(index++);
- if (adc != null) {
- String[] values = adc.split(",");
+ if (parser.hasNext()) {
+ String[] values = parser.next().split(",");
for (int i = 0; i < values.length; i++) {
position.set(Event.PREFIX_ADC + (i + 1), Integer.parseInt(values[i], 16));
}
}
- position.set(Event.KEY_ODOMETER, parser.group(index++));
+ position.set(Event.KEY_ODOMETER, parser.next());
+ position.set(Event.KEY_RFID, parser.next());
- // Driver
- position.set(Event.KEY_RFID, parser.group(index++));
-
- // Other
- String status = parser.group(index++);
- if (status != null) {
- int value = Integer.parseInt(status, 16);
+ if (parser.hasNext()) {
+ int value = parser.nextInt(16);
position.set(Event.KEY_BATTERY, value >> 8);
position.set(Event.KEY_GSM, (value >> 4) & 0xf);
position.set(Event.KEY_SATELLITES, value & 0xf);
@@ -153,4 +107,5 @@ public class Pt502ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+
}
diff --git a/src/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/org/traccar/protocol/RuptelaProtocolDecoder.java
index 45925d5d1..ede92d837 100644
--- a/src/org/traccar/protocol/RuptelaProtocolDecoder.java
+++ b/src/org/traccar/protocol/RuptelaProtocolDecoder.java
@@ -37,14 +37,12 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
buf.readUnsignedShort(); // data length
- // Identify device
String imei = String.format("%015d", buf.readLong());
if (!identify(imei, channel)) {
return null;
@@ -63,19 +61,16 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
- // Time
position.setTime(new Date(buf.readUnsignedInt() * 1000));
buf.readUnsignedByte(); // timestamp extension
buf.readUnsignedByte(); // priority (reserved)
- // Location
position.setLongitude(buf.readInt() / 10000000.0);
position.setLatitude(buf.readInt() / 10000000.0);
position.setAltitude(buf.readUnsignedShort() / 10.0);
position.setCourse(buf.readUnsignedShort() / 100.0);
- // Validity
int satellites = buf.readUnsignedByte();
position.set(Event.KEY_SATELLITES, satellites);
position.setValid(satellites >= 3);
@@ -109,13 +104,13 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
for (int j = 0; j < cnt; j++) {
position.set(Event.PREFIX_IO + buf.readUnsignedByte(), buf.readLong());
}
+
positions.add(position);
}
- // Acknowledgement
if (channel != null) {
byte[] response = {0x00, 0x02, 0x64, 0x01, 0x13, (byte) 0xbc};
- channel.write(ChannelBuffers.wrappedBuffer(response));
+ channel.write(ChannelBuffers.wrappedBuffer(response)); // acknowledgement
}
return positions;
diff --git a/src/org/traccar/protocol/Stl060ProtocolDecoder.java b/src/org/traccar/protocol/Stl060ProtocolDecoder.java
index b5b972982..b583aee66 100644
--- a/src/org/traccar/protocol/Stl060ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Stl060ProtocolDecoder.java
@@ -21,6 +21,7 @@ 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;
@@ -30,38 +31,40 @@ public class Stl060ProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- ".*\\$1," +
- "(\\d+)," + // IMEI
- "D001," + // Type
- "[^,]*," + // Vehicle
- "(\\d{2})/(\\d{2})/(\\d{2})," + // Date
- "(\\d{2}):(\\d{2}):(\\d{2})," + // Time
- "(\\d{2})(\\d{2})\\.?(\\d+)([NS])," + // Latitude
- "(\\d{3})(\\d{2})\\.?(\\d+)([EW])," + // Longitude
- "(\\d+\\.?\\d*)," + // Speed
- "(\\d+\\.?\\d*)," + // Course
-
- "(?:(\\d+)," + // Odometer
- "(\\d+)," + // Ignition
- "(\\d+)," + // DI1
- "(\\d+)," + // DI2
- "(\\d+),|" + // Fuel
-
- "([01])," + // Charging
- "([01])," + // Ignition
- "0,0," + // Reserved
- "(\\d+)," + // DI
- "([^,]+)," + // RFID
- "(\\d+)," + // Odometer
- "(\\d+)," + // Temperature
- "(\\d+)," + // Fuel
- "([01])," + // Accelerometer
- "([01])," + // DO1
- "([01]),)" + // DO2
-
- "([AV])" + // Validity
- ".*");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .any()
+ .text("$1,")
+ .number("(d+),") // imei
+ .text("D001,") // type
+ .expression("[^,]*,") // vehicle
+ .number("(dd)/(dd)/(dd),") // date
+ .number("(dd):(dd):(dd),") // time
+ .number("(dd)(dd).?(d+)([NS]),") // latitude
+ .number("(ddd)(dd).?(d+)([EW]),") // longitude
+ .number("(d+.?d*),") // speed
+ .number("(d+.?d*),") // course
+ .groupBegin()
+ .number("(d+),") // odometer
+ .number("(d+),") // Ignition
+ .number("(d+),") // di1
+ .number("(d+),") // di2
+ .number("(d+),") // fuel
+ .or()
+ .expression("([01]),") // charging
+ .expression("([01]),") // ignition
+ .expression("0,0,") // reserved
+ .number("(d+),") // di
+ .expression("([^,]+),") // rfid
+ .number("(d+),") // odometer
+ .number("(d+),") // temperature
+ .number("(d+),") // fuel
+ .expression("([01]),") // accelerometer
+ .expression("([01]),") // do1
+ .expression("([01]),") // do2
+ .groupEnd()
+ .expression("([AV])") // validity
+ .any()
+ .compile();
@Override
protected Object decode(
diff --git a/src/org/traccar/protocol/SuntechProtocolDecoder.java b/src/org/traccar/protocol/SuntechProtocolDecoder.java
index 19eed1197..81a7c3041 100644
--- a/src/org/traccar/protocol/SuntechProtocolDecoder.java
+++ b/src/org/traccar/protocol/SuntechProtocolDecoder.java
@@ -16,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
@@ -32,82 +32,66 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "S.\\d{3}(?:\\w{3})?;" + // Header
- "(?:([^;]+);)?" + // Type
- "(\\d{6,});" + // Device ID
- "(?:\\d+;)?" +
- "(\\d+);" + // Version
- "(\\d{4})(\\d{2})(\\d{2});" + // Date (YYYYMMDD)
- "(\\d{2}):(\\d{2}):(\\d{2});" + // Time (HH:MM:SS)
- "(?:(\\p{XDigit}+);)?" + // Cell
- "([-\\+]\\d{2}\\.\\d+);" + // Latitude
- "([-\\+]\\d{3}\\.\\d+);" + // Longitude
- "(\\d{3}\\.\\d{3});" + // Speed
- "(\\d{3}\\.\\d{2});" + // Course
- "(?:\\d+;)?" +
- "(\\d+\\.\\d+)?" + // Battery
- ".*"); // Full format
+ private static final Pattern PATTERN = new PatternBuilder()
+ .expression("S.")
+ .number("ddd")
+ .expression("(?:[A-Z]{3})?;") // header
+ .expression("([^;]+);").optional() // type
+ .number("(d{6,});") // device id
+ .number("d+;").optional()
+ .number("(d+);") // version
+ .number("(dddd)(dd)(dd);") // date
+ .number("(dd):(dd):(dd);") // time
+ .number("(x+);").optional() // cell
+ .number("([-+]dd.d+);") // latitude
+ .number("([-+]ddd.d+);") // longitude
+ .number("(ddd.ddd);") // speed
+ .number("(ddd.dd);") // course
+ .number("d+;").optional()
+ .number("(d+.d+)?") // battery
+ .any() // full format
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String sentence = (String) msg;
-
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- int index = 1;
- String type = parser.group(index++);
- if (type != null && (type.equals("Alert") || type.equals("Emergency"))) {
- position.set(Event.KEY_ALARM, true);
+ if (parser.hasNext()) {
+ String type = parser.next();
+ if (type.equals("Alert") || type.equals("Emergency")) {
+ position.set(Event.KEY_ALARM, true);
+ }
}
- // Identifier
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Version
- position.set(Event.KEY_VERSION, parser.group(index++));
-
- // Date and Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
-
- // Cell
- position.set(Event.KEY_CELL, parser.group(index++));
+ position.set(Event.KEY_VERSION, parser.next());
- // Coordinates
- position.setLatitude(Double.parseDouble(parser.group(index++)));
- position.setLongitude(Double.parseDouble(parser.group(index++)));
- position.setValid(true); // wrong?
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Speed
- position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(parser.group(index++))));
+ position.set(Event.KEY_CELL, parser.next());
- // Course
- position.setCourse(Double.parseDouble(parser.group(index++)));
+ position.setValid(true);
+ position.setLatitude(parser.nextDouble());
+ position.setLongitude(parser.nextDouble());
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
- // Battery
- position.set(Event.KEY_BATTERY, parser.group(index++));
+ position.set(Event.KEY_BATTERY, parser.next());
return position;
}
diff --git a/src/org/traccar/protocol/T55ProtocolDecoder.java b/src/org/traccar/protocol/T55ProtocolDecoder.java
index 42db4c753..d8b3eefe8 100644
--- a/src/org/traccar/protocol/T55ProtocolDecoder.java
+++ b/src/org/traccar/protocol/T55ProtocolDecoder.java
@@ -82,6 +82,8 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
.any()
.compile();
+ private Position position = null;
+
private Position decodeGprmc(String sentence, Channel channel) {
if (channel != null) {
@@ -95,7 +97,10 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position();
position.setProtocol(getProtocolName());
- position.setDeviceId(getDeviceId());
+
+ if (hasDeviceId()) {
+ position.setDeviceId(getDeviceId());
+ }
DateBuilder dateBuilder = new DateBuilder()
.setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
@@ -109,7 +114,12 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
position.setTime(dateBuilder.getDate());
- return position;
+ if (hasDeviceId()) {
+ return position;
+ } else {
+ this.position = position; // save position
+ return null;
+ }
}
private Position decodeGpgga(String sentence) {
@@ -207,10 +217,15 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
} else if (sentence.startsWith("IMEI")) {
identify(sentence.substring(5, sentence.length()), channel);
} else if (sentence.startsWith("$GPFID")) {
- identify(sentence.substring(6, sentence.length()), channel);
+ if (identify(sentence.substring(6, sentence.length()), channel) && position != null) {
+ Position position = this.position;
+ position.setDeviceId(getDeviceId());
+ this.position = null;
+ return position;
+ }
} else if (Character.isDigit(sentence.charAt(0)) && sentence.length() == 15) {
identify(sentence, channel);
- } else if (sentence.startsWith("$GPRMC") && hasDeviceId()) {
+ } else if (sentence.startsWith("$GPRMC")) {
return decodeGprmc(sentence, channel);
} else if (sentence.startsWith("$GPGGA") && hasDeviceId()) {
return decodeGpgga(sentence);
diff --git a/src/org/traccar/protocol/T800xProtocol.java b/src/org/traccar/protocol/T800xProtocol.java
new file mode 100644
index 000000000..f98dfc943
--- /dev/null
+++ b/src/org/traccar/protocol/T800xProtocol.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015 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 T800xProtocol extends BaseProtocol {
+
+ public T800xProtocol() {
+ super("t800x");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ServerBootstrap(), getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 3, 2, -5, 0));
+ pipeline.addLast("objectDecoder", new T800xProtocolDecoder(T800xProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/T800xProtocolDecoder.java b/src/org/traccar/protocol/T800xProtocolDecoder.java
new file mode 100644
index 000000000..ab62110ba
--- /dev/null
+++ b/src/org/traccar/protocol/T800xProtocolDecoder.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2015 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.ChannelBufferTools;
+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.ByteOrder;
+
+public class T800xProtocolDecoder extends BaseProtocolDecoder {
+
+ public T800xProtocolDecoder(T800xProtocol protocol) {
+ super(protocol);
+ }
+
+ private static final int MSG_LOGIN = 0x01;
+ private static final int MSG_GPS = 0x02;
+ private static final int MSG_HEARTBEAT = 0x03;
+ private static final int MSG_ALARM = 0x04;
+
+ private static float readSwappedFloat(ChannelBuffer buf) {
+ byte[] bytes = new byte[4];
+ buf.readBytes(bytes);
+ return ChannelBuffers.wrappedBuffer(ByteOrder.LITTLE_ENDIAN, bytes).readFloat();
+ }
+
+ private void sendResponse(Channel channel, int type, ChannelBuffer imei) {
+ if (channel != null) {
+ ChannelBuffer response = ChannelBuffers.directBuffer(15);
+ response.writeByte(0x23);
+ response.writeByte(0x23); // header
+ response.writeByte(type);
+ response.writeShort(response.capacity()); // length
+ response.writeShort(0x0001); // index
+ response.writeBytes(imei);
+ channel.write(response);
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ChannelBuffer buf = (ChannelBuffer) msg;
+
+ buf.skipBytes(2);
+ int type = buf.readUnsignedByte();
+ buf.readUnsignedShort(); // length
+ int index = buf.readUnsignedShort();
+ ChannelBuffer imei = buf.readBytes(8);
+
+ if (!identify(ChannelBuffers.hexDump(imei).substring(1), channel, remoteAddress)) {
+ return null;
+ }
+
+ if (type == MSG_LOGIN || type == MSG_ALARM || type == MSG_HEARTBEAT) {
+ sendResponse(channel, type, imei);
+ }
+
+ if (type == MSG_GPS || type == MSG_ALARM) {
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(getDeviceId());
+
+ position.set(Event.KEY_INDEX, index);
+
+ buf.readUnsignedShort(); // acc on interval
+ buf.readUnsignedShort(); // acc off interval
+ buf.readUnsignedByte(); // angle compensation
+ buf.readUnsignedShort(); // distance compensation
+ buf.readUnsignedShort(); // speed alarm
+
+ int locationStatus = buf.readUnsignedByte();
+
+ buf.readUnsignedByte(); // gsensor manager status
+ buf.readUnsignedByte(); // other flags
+ buf.readUnsignedByte(); // heartbeat
+ buf.readUnsignedByte(); // relay status
+ buf.readUnsignedShort(); // drag alarm setting
+
+ int io = buf.readUnsignedShort();
+ position.set(Event.KEY_IGNITION, BitUtil.check(io, 14));
+ position.set("ac", BitUtil.check(io, 13));
+
+ position.set(Event.PREFIX_ADC + 1, buf.readUnsignedShort());
+ position.set(Event.PREFIX_ADC + 2, buf.readUnsignedShort());
+
+ position.set(Event.KEY_ALARM, buf.readUnsignedByte());
+
+ buf.readUnsignedByte(); // reserved
+
+ position.set(Event.KEY_ODOMETER, buf.readUnsignedInt());
+
+ int battery = ChannelBufferTools.readHexInteger(buf, 2);
+ if (battery == 0) {
+ battery = 100;
+ }
+ position.set(Event.KEY_BATTERY, battery);
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setYear(ChannelBufferTools.readHexInteger(buf, 2))
+ .setMonth(ChannelBufferTools.readHexInteger(buf, 2))
+ .setDay(ChannelBufferTools.readHexInteger(buf, 2))
+ .setHour(ChannelBufferTools.readHexInteger(buf, 2))
+ .setMinute(ChannelBufferTools.readHexInteger(buf, 2))
+ .setSecond(ChannelBufferTools.readHexInteger(buf, 2));
+
+ if (BitUtil.check(locationStatus, 6)) {
+
+ position.setValid(!BitUtil.check(locationStatus, 7));
+ position.setTime(dateBuilder.getDate());
+ position.setAltitude(readSwappedFloat(buf));
+ position.setLongitude(readSwappedFloat(buf));
+ position.setLatitude(readSwappedFloat(buf));
+ position.setSpeed(UnitsConverter.knotsFromKph(
+ ChannelBufferTools.readHexInteger(buf, 4) * 0.1));
+ position.setCourse(buf.readUnsignedShort());
+
+ } else {
+
+ getLastLocation(position, dateBuilder.getDate());
+
+ position.set(Event.KEY_MCC, buf.readUnsignedShort());
+ position.set(Event.KEY_MNC, buf.readUnsignedShort());
+ position.set(Event.KEY_LAC, buf.readUnsignedShort());
+ position.set(Event.KEY_CELL, buf.readUnsignedShort());
+
+ // two more cell towers
+
+ }
+
+ return position;
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/protocol/TaipProtocolDecoder.java b/src/org/traccar/protocol/TaipProtocolDecoder.java
index 860dd4602..7f8c1a3c6 100644
--- a/src/org/traccar/protocol/TaipProtocolDecoder.java
+++ b/src/org/traccar/protocol/TaipProtocolDecoder.java
@@ -16,13 +16,13 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
import java.util.Date;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.Position;
@@ -35,44 +35,41 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
this.sendResponse = sendResponse;
}
- private static final Pattern PATTERN = Pattern.compile(
- "(?:R[EP]V" + // Type
- "(?:\\d{2}" + // Event index
- "(\\d{4})" + // Week
- "(\\d))?" + // Day
- "(\\d{5})|" + // Seconds
- "RGP" + // Type
- "(\\d{2})(\\d{2})(\\d{2})" + // Date
- "(\\d{2})(\\d{2})(\\d{2}))" + // Time
- "([\\+\\-]\\d{2})(\\d{5})" + // Latitude
- "([\\+\\-]\\d{3})(\\d{5})" + // Longitude
- "(\\d{3})" + // Speed
- "(\\d{3})" + // Course
- "(\\d)" + // Fix mode
- ".*\r?\n?");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .groupBegin()
+ .expression("R[EP]V") // type
+ .groupBegin()
+ .number("dd") // event index
+ .number("(dddd)") // week
+ .number("(d)") // day
+ .groupEnd("?")
+ .number("(d{5})") // seconds
+ .or()
+ .text("RGP") // type
+ .number("(dd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd)") // time
+ .groupEnd()
+ .number("([-+]dd)(d{5})") // latitude
+ .number("([-+]ddd)(d{5})") // longitude
+ .number("(ddd)") // speed
+ .number("(ddd)") // course
+ .number("(d)") // fix mode
+ .any()
+ .compile();
private Date getTime(long week, long day, long seconds) {
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 1980);
- time.set(Calendar.MONTH, 0);
- time.set(Calendar.DAY_OF_MONTH, 6);
-
- long millis = time.getTimeInMillis();
- millis += ((week * 7 + day) * 24 * 60 * 60 + seconds) * 1000;
-
- return new Date(millis);
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(1980, 1, 6)
+ .addMillis(((week * 7 + day) * 24 * 60 * 60 + seconds) * 1000);
+ return dateBuilder.getDate();
}
private Date getTime(long seconds) {
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.set(Calendar.HOUR_OF_DAY, 0);
- time.set(Calendar.MINUTE, 0);
- time.set(Calendar.SECOND, 0);
- time.set(Calendar.MILLISECOND, 0);
-
- long millis = time.getTimeInMillis() + seconds * 1000;
+ DateBuilder dateBuilder = new DateBuilder(new Date())
+ .setTime(0, 0, 0, 0)
+ .addMillis(seconds * 1000);
+ long millis = dateBuilder.getDate().getTime();
long diff = System.currentTimeMillis() - millis;
if (diff > 12 * 60 * 60 * 1000) {
@@ -86,8 +83,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
@@ -97,7 +93,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
sentence = sentence.substring(beginIndex + 1);
}
- // Find device ID
+ // Find device identifier
beginIndex = sentence.indexOf(";ID=");
if (beginIndex != -1) {
beginIndex += 4;
@@ -106,13 +102,11 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
endIndex = sentence.length();
}
- // Find device in database
String id = sentence.substring(beginIndex, endIndex);
if (!identify(id, channel)) {
return null;
}
- // Send response
if (sendResponse && channel != null) {
channel.write(id);
}
@@ -120,58 +114,39 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
position.setDeviceId(getDeviceId());
- Integer index = 1;
-
- // Time
- String week = parser.group(index++);
- String day = parser.group(index++);
- String seconds = parser.group(index++);
+ String week = parser.next();
+ String day = parser.next();
+ String seconds = parser.next();
if (seconds != null) {
if (week != null && day != null) {
position.setTime(getTime(Integer.parseInt(week), Integer.parseInt(day), Integer.parseInt(seconds)));
} else {
position.setTime(getTime(Integer.parseInt(seconds)));
}
- index += 6;
- } else {
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
}
- // Latitude
- String latitude = parser.group(index) + '.' + parser.group(index + 1);
- index += 2;
- position.setLatitude(Double.parseDouble(latitude));
-
- // Latitude
- String longitude = parser.group(index) + '.' + parser.group(index + 1);
- index += 2;
- position.setLongitude(Double.parseDouble(longitude));
+ if (parser.hasNext(6)) {
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+ }
- // Speed and Course
- position.setSpeed(UnitsConverter.knotsFromMph(Double.parseDouble(parser.group(index++))));
- position.setCourse(Double.parseDouble(parser.group(index++)));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_DEG));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_DEG));
+ position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
+ position.setValid(parser.nextInt() != 0);
- // Validity
- position.setValid(Integer.parseInt(parser.group(index++)) != 0);
return position;
}
diff --git a/src/org/traccar/protocol/TelikProtocolDecoder.java b/src/org/traccar/protocol/TelikProtocolDecoder.java
index 255a3032b..8ad88c868 100644
--- a/src/org/traccar/protocol/TelikProtocolDecoder.java
+++ b/src/org/traccar/protocol/TelikProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2014 - 2015 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,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
@@ -31,74 +31,54 @@ public class TelikProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "\\d{4}" +
- "(\\d{6})" + // Device ID
- "(\\d+)," + // Type
- "\\d{12}," + // Event Time
- "\\d+," +
- "(\\d{2})(\\d{2})(\\d{2})" + // Date
- "(\\d{2})(\\d{2})(\\d{2})," + // Time
- "(-?\\d+)," + // Longitude
- "(-?\\d+)," + // Latitude
- "(\\d)," + // Validity
- "(\\d+)," + // Speed
- "(\\d+)," + // Course
- "(\\d+)," + // Satellites
- ".*");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .number("dddd")
+ .number("(d{6})") // device id
+ .number("(d+),") // type
+ .number("d{12},") // event time
+ .number("d+,")
+ .number("(dd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd),") // time
+ .number("(-?d+),") // longitude
+ .number("(-?d+),") // latitude
+ .number("(d),") // validity
+ .number("(d+),") // speed
+ .number("(d+),") // course
+ .number("(d+),") // satellites
+ .any()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- // Parse message
- Matcher parser = PATTERN.matcher((String) msg);
+ Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
-
- // Get device by IMEI
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Message type
- position.set(Event.KEY_TYPE, parser.group(index++));
-
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
-
- // Location
- position.setLongitude(Double.parseDouble(parser.group(index++)) / 10000);
- position.setLatitude(Double.parseDouble(parser.group(index++)) / 10000);
-
- // Validity
- position.setValid(parser.group(index++).compareTo("1") != 0);
+ position.set(Event.KEY_TYPE, parser.next());
- // Speed
- position.setSpeed(Double.parseDouble(parser.group(index++)));
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Course
- position.setCourse(Double.parseDouble(parser.group(index++)));
+ position.setLongitude(parser.nextDouble() / 10000);
+ position.setLatitude(parser.nextDouble() / 10000);
+ position.setValid(parser.nextInt() != 1);
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
- // Satellites
- position.set(Event.KEY_SATELLITES, parser.group(index++));
+ position.set(Event.KEY_SATELLITES, parser.next());
return position;
}
diff --git a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
index d3bca57ce..830df2b96 100644
--- a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
+++ b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
@@ -200,8 +200,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ChannelBuffer buf = (ChannelBuffer) msg;
diff --git a/src/org/traccar/protocol/Tk102ProtocolDecoder.java b/src/org/traccar/protocol/Tk102ProtocolDecoder.java
index e9fb86cc2..386f465a5 100644
--- a/src/org/traccar/protocol/Tk102ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Tk102ProtocolDecoder.java
@@ -41,7 +41,7 @@ public class Tk102ProtocolDecoder extends BaseProtocolDecoder {
.expression("([AV])") // validity
.number("(dd)(dd.dddd)([NS])") // latitude
.number("(ddd)(dd.dddd)([EW])") // longitude
- .number("(ddd.ddd)") // Speed
+ .number("(ddd.ddd)") // speed
.number("(dd)(dd)(dd)") // date (ddmmyy)
.number("d+")
.any()
diff --git a/src/org/traccar/protocol/Tk103ProtocolDecoder.java b/src/org/traccar/protocol/Tk103ProtocolDecoder.java
index 73ab08b59..95728c447 100644
--- a/src/org/traccar/protocol/Tk103ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Tk103ProtocolDecoder.java
@@ -38,7 +38,7 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
.number("(d+)(,)?") // device id
.expression(".{4},?") // command
.number("d*") // imei?
- .number("(dd)(dd)(dd),?") // date (yymmdd)
+ .number("(dd)(dd)(dd),?") // date
.expression("([AV]),?") // validity
.number("(dd)(dd.d+)") // latitude
.expression("([NS]),?")
@@ -53,6 +53,17 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
.text(")").optional()
.compile();
+ private static final Pattern PATTERN_BATTERY = new PatternBuilder()
+ .number("(d+),") // device id
+ .text("ZC20,")
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .number("(dd)(dd)(dd),") // time
+ .number("d+,") // battery level
+ .number("(d+),") // battery voltage
+ .number("(d+),") // power voltage
+ .number("d+") // installed
+ .compile();
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -77,7 +88,36 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
}
}
- Parser parser = new Parser(PATTERN, sentence);
+ Parser parser = new Parser(PATTERN_BATTERY, sentence);
+ if (parser.matches()) {
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+
+ if (!identify(parser.next(), channel)) {
+ return null;
+ }
+ position.setDeviceId(getDeviceId());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+
+ getLastLocation(position, dateBuilder.getDate());
+
+ int battery = parser.nextInt();
+ if (battery != 65535) {
+ position.set(Event.KEY_BATTERY, battery);
+ }
+
+ int power = parser.nextInt();
+ if (power != 65535) {
+ position.set(Event.KEY_POWER, battery);
+ }
+
+ return position;
+ }
+
+ parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
return null;
}
diff --git a/src/org/traccar/protocol/Tr20ProtocolDecoder.java b/src/org/traccar/protocol/Tr20ProtocolDecoder.java
index 069757820..fac0f8ee9 100644
--- a/src/org/traccar/protocol/Tr20ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Tr20ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2012 - 2015 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,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.Position;
@@ -31,98 +31,65 @@ public class Tr20ProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN_PING = Pattern.compile(
- "%%[^,]+,(\\d+)");
-
- private static final Pattern PATTERN_DATA = Pattern.compile(
- "%%" +
- "([^,]+)," + // Id
- "([AL])," + // Validity
- "(\\d{2})(\\d{2})(\\d{2})" + // Date (YYMMDD)
- "(\\d{2})(\\d{2})(\\d{2})," + // Time (HHMMSS)
- "([NS])" +
- "(\\d{2})(\\d{2}\\.\\d+)" + // Latitude (DDMM.MMMM)
- "([EW])" +
- "(\\d{3})(\\d{2}\\.\\d+)," + // Longitude (DDDMM.MMMM)
- "(\\d+)," + // Speed
- "(\\d+)," + // Course
- ".*");
+ private static final Pattern PATTERN_PING = new PatternBuilder()
+ .text("%%")
+ .expression("[^,]+,")
+ .number("(d+)")
+ .compile();
+
+ private static final Pattern PATTERN_DATA = new PatternBuilder()
+ .text("%%")
+ .expression("([^,]+),") // id
+ .expression("([AL]),") // validity
+ .number("(dd)(dd)(dd)") // date (yymmdd)
+ .number("(dd)(dd)(dd),") // time
+ .expression("([NS])")
+ .number("(dd)(dd.d+)") // latitude
+ .expression("([EW])")
+ .number("(ddd)(dd.d+),") // longitude
+ .number("(d+),") // speed
+ .number("(d+),") // course
+ .any()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
-
- String sentence = (String) msg;
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- // Keep alive message
- Matcher parser = PATTERN_PING.matcher(sentence);
+ Parser parser = new Parser(PATTERN_PING, (String) msg);
if (parser.matches()) {
-
- // Send response
if (channel != null) {
- channel.write("&&" + parser.group(1) + "\r\n");
- }
- } else {
-
- // Data message parse
- parser = PATTERN_DATA.matcher(sentence);
-
- // Unknown message
- if (!parser.matches()) {
- return null;
+ channel.write("&&" + parser.next() + "\r\n"); // keep-alive response
}
+ return null;
+ }
- // Create new position
- Position position = new Position();
- position.setProtocol(getProtocolName());
-
- Integer index = 1;
-
- // Get device by id
- if (!identify(parser.group(index++), channel)) {
- return null;
- }
- position.setDeviceId(getDeviceId());
-
- // Validity
- position.setValid(parser.group(index++).compareTo("A") == 0);
-
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
+ parser = new Parser(PATTERN_DATA, (String) msg);
+ if (!parser.matches()) {
+ return null;
+ }
- // Latitude
- int hemisphere = 1;
- if (parser.group(index++).compareTo("S") == 0) hemisphere = -1;
- Double latitude = Double.parseDouble(parser.group(index++));
- latitude += Double.parseDouble(parser.group(index++)) / 60;
- position.setLatitude(latitude * hemisphere);
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
- // Longitude
- hemisphere = 1;
- if (parser.group(index++).compareTo("W") == 0) hemisphere = -1;
- Double longitude = Double.parseDouble(parser.group(index++));
- longitude += Double.parseDouble(parser.group(index++)) / 60;
- position.setLongitude(longitude * hemisphere);
+ if (!identify(parser.next(), channel)) {
+ return null;
+ }
+ position.setDeviceId(getDeviceId());
- // Speed
- position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(parser.group(index++))));
+ position.setValid(parser.next().equals("A"));
- // Course
- position.setCourse(Double.parseDouble(parser.group(index++)));
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- return position;
- }
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
- return null;
+ return position;
}
}
diff --git a/src/org/traccar/protocol/Tr900ProtocolDecoder.java b/src/org/traccar/protocol/Tr900ProtocolDecoder.java
index f8d0a7a5c..b3500d552 100644
--- a/src/org/traccar/protocol/Tr900ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Tr900ProtocolDecoder.java
@@ -16,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
@@ -31,93 +31,65 @@ public class Tr900ProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- ">(\\d+)," + // ID
- "\\d+," + // Period
- "(\\d)," + // Fix
- "(\\d{2})(\\d{2})(\\d{2})," + // Date (YYMMDD)
- "(\\d{2})(\\d{2})(\\d{2})," + // Time (HHMMSS)
- "([EW])" +
- "(\\d{3})(\\d{2}\\.\\d+)," + // Longitude (DDDMM.MMMM)
- "([NS])" +
- "(\\d{2})(\\d{2}\\.\\d+)," + // Latitude (DDMM.MMMM)
- "[^,]*," + // Command
- "(\\d+\\.?\\d*)," + // Speed
- "(\\d+\\.?\\d*)," + // Course
- "(\\d+)," + // GSM
- "(\\d+)," + // Event
- "(\\d+)-" + // ADC
- "(\\d+)," + // Battery
- "\\d+," + // Impulses
- "(\\d+)," + // Input
- "(\\d+)" + // Status
- ".*(?:\r\n)?");
+ private static final Pattern PATTERN = new PatternBuilder()
+ .number(">(d+),") // id
+ .number("d+,") // period
+ .number("(d),") // fix
+ .number("(dd)(dd)(dd),") // date (yymmdd)
+ .number("(dd)(dd)(dd),") // time
+ .expression("([EW])")
+ .number("(ddd)(dd.d+),") // longitude
+ .expression("([NS])")
+ .number("(dd)(dd.d+),") // latitude
+ .expression("[^,]*,") // command
+ .number("(d+.?d*),") // speed
+ .number("(d+.?d*),") // course
+ .number("(d+),") // gsm
+ .number("(d+),") // event
+ .number("(d+)-") // adc
+ .number("(d+),") // battery
+ .number("d+,") // impulses
+ .number("(d+),") // input
+ .number("(d+)") // status
+ .any()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String sentence = (String) msg;
-
- // Parse message
- Matcher parser = PATTERN.matcher(sentence);
+ Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- Integer index = 1;
- // Identification
- if (!identify(parser.group(index++), channel, remoteAddress)) {
+ if (!identify(parser.next(), channel, remoteAddress)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Validity
- position.setValid(parser.group(index++).compareTo("1") == 0);
-
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
-
- // Longitude
- String hemisphere = parser.group(index++);
- Double longitude = Double.parseDouble(parser.group(index++));
- longitude += Double.parseDouble(parser.group(index++)) / 60;
- if (hemisphere.compareTo("W") == 0) longitude = -longitude;
- position.setLongitude(longitude);
+ position.setValid(parser.nextInt() == 1);
- // Latitude
- hemisphere = parser.group(index++);
- Double latitude = Double.parseDouble(parser.group(index++));
- latitude += Double.parseDouble(parser.group(index++)) / 60;
- if (hemisphere.compareTo("S") == 0) latitude = -latitude;
- position.setLatitude(latitude);
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Speed
- position.setSpeed(Double.parseDouble(parser.group(index++)));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN));
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
- // Course
- position.setCourse(Double.parseDouble(parser.group(index++)));
+ position.set(Event.KEY_GSM, parser.next());
+ position.set(Event.KEY_EVENT, parser.nextInt());
+ position.set(Event.PREFIX_ADC + 1, parser.nextInt());
+ position.set(Event.KEY_BATTERY, parser.nextInt());
+ position.set(Event.KEY_INPUT, parser.next());
+ position.set(Event.KEY_STATUS, parser.next());
- // Other
- position.set(Event.KEY_GSM, parser.group(index++));
- position.set(Event.KEY_EVENT, Integer.parseInt(parser.group(index++)));
- position.set(Event.PREFIX_ADC + 1, Integer.parseInt(parser.group(index++)));
- position.set(Event.KEY_BATTERY, Integer.parseInt(parser.group(index++)));
- position.set(Event.KEY_INPUT, parser.group(index++));
- position.set(Event.KEY_STATUS, parser.group(index++));
return position;
}
diff --git a/src/org/traccar/protocol/TrackboxProtocolDecoder.java b/src/org/traccar/protocol/TrackboxProtocolDecoder.java
index 39b1662ea..bf4c4f34d 100644
--- a/src/org/traccar/protocol/TrackboxProtocolDecoder.java
+++ b/src/org/traccar/protocol/TrackboxProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2014 - 2015 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,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
@@ -31,18 +31,19 @@ public class TrackboxProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "(\\d{2})(\\d{2})(\\d{2})\\.(\\d{3})," + // Time
- "(\\d{2})(\\d{2}\\.\\d{4})([NS])," + // Latitude (DDMM.MMMM)
- "(\\d{3})(\\d{2}\\.\\d{4})([EW])," + // Longitude (DDDMM.MMMM)
- "(\\d+\\.\\d)," + // HDOP
- "(-?\\d+\\.?\\d*)," + // Altitude
- "(\\d)," + // Fix Type
- "(\\d+\\.\\d+)," + // Course
- "(\\d+\\.\\d+)," + // Speed (kph)
- "(\\d+\\.\\d+)," + // Speed (knots)
- "(\\d{2})(\\d{2})(\\d{2})," + // Date
- "(\\d+)"); // Satellites
+ private static final Pattern PATTERN = new PatternBuilder()
+ .number("(dd)(dd)(dd).(ddd),") // time
+ .number("(dd)(dd.dddd)([NS]),") // latitude
+ .number("(ddd)(dd.dddd)([EW]),") // longitude
+ .number("(d+.d),") // hdop
+ .number("(-?d+.?d*),") // altitude
+ .number("(d),") // fix type
+ .number("(d+.d+),") // course
+ .number("d+.d+,") // speed (kph)
+ .number("(d+.d+),") // speed (knots)
+ .number("(dd)(dd)(dd),") // date
+ .number("(d+)") // satellites
+ .compile();
private void sendResponse(Channel channel) {
if (channel != null) {
@@ -52,83 +53,51 @@ public class TrackboxProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
if (sentence.startsWith("a=connect")) {
-
String id = sentence.substring(sentence.indexOf("i=") + 2);
if (identify(id, channel)) {
sendResponse(channel);
}
+ return null;
+ }
- } else {
-
- Matcher parser = PATTERN.matcher(sentence);
- if (!parser.matches()) {
- return null;
- }
- sendResponse(channel);
-
- Position position = new Position();
- position.setDeviceId(getDeviceId());
- position.setProtocol(getProtocolName());
-
- Integer index = 1;
-
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MILLISECOND, Integer.parseInt(parser.group(index++)));
-
- // Latitude
- Double latitude = Double.parseDouble(parser.group(index++));
- latitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("S") == 0) latitude = -latitude;
- position.setLatitude(latitude);
-
- // Longitude
- Double longitude = Double.parseDouble(parser.group(index++));
- longitude += Double.parseDouble(parser.group(index++)) / 60;
- if (parser.group(index++).compareTo("W") == 0) longitude = -longitude;
- position.setLongitude(longitude);
-
- // HDOP
- position.set(Event.KEY_HDOP, parser.group(index++));
-
- // Altitude
- position.setAltitude(Double.parseDouble(parser.group(index++)));
-
- // Validity
- int fix = Integer.parseInt(parser.group(index++));
- position.set(Event.KEY_GPS, fix);
- position.setValid(fix > 0);
-
- // Course
- position.setCourse(Double.parseDouble(parser.group(index++)));
-
- // Speed
- index += 1; // speed in kph
- position.setSpeed(Double.parseDouble(parser.group(index++)));
-
- // Date
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.YEAR, 2000 + Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
-
- // Satellites
- position.set(Event.KEY_SATELLITES, parser.group(index++));
-
- return position;
+ Parser parser = new Parser(PATTERN, sentence);
+ if (!parser.matches()) {
+ return null;
}
+ sendResponse(channel);
+
+ Position position = new Position();
+ position.setDeviceId(getDeviceId());
+ position.setProtocol(getProtocolName());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt());
+
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+
+ position.set(Event.KEY_HDOP, parser.next());
+
+ position.setAltitude(parser.nextDouble());
+
+ int fix = parser.nextInt();
+ position.set(Event.KEY_GPS, fix);
+ position.setValid(fix > 0);
+
+ position.setCourse(parser.nextDouble());
+ position.setSpeed(parser.nextDouble());
+
+ dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+
+ position.set(Event.KEY_SATELLITES, parser.next());
- return null;
+ return position;
}
}
diff --git a/src/org/traccar/protocol/TramigoProtocolDecoder.java b/src/org/traccar/protocol/TramigoProtocolDecoder.java
index be97f24fd..456086fe2 100644
--- a/src/org/traccar/protocol/TramigoProtocolDecoder.java
+++ b/src/org/traccar/protocol/TramigoProtocolDecoder.java
@@ -105,7 +105,6 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder {
String sentence = buf.toString(Charset.defaultCharset());
- // Coordinates
Pattern pattern = Pattern.compile("(-?\\d+\\.\\d+), (-?\\d+\\.\\d+)");
Matcher matcher = pattern.matcher(sentence);
if (!matcher.find()) {
@@ -114,7 +113,6 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder {
position.setLatitude(Double.parseDouble(matcher.group(1)));
position.setLongitude(Double.parseDouble(matcher.group(2)));
- // Speed and Course
pattern = Pattern.compile("([NSWE]{1,2}) with speed (\\d+) km/h");
matcher = pattern.matcher(sentence);
if (matcher.find()) {
@@ -122,7 +120,6 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder {
position.setCourse(0); // matcher.group(1) for course
}
- // Time
pattern = Pattern.compile("(\\d{1,2}:\\d{2} \\w{3} \\d{1,2})");
matcher = pattern.matcher(sentence);
if (!matcher.find()) {
@@ -130,6 +127,7 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder {
}
DateFormat dateFormat = new SimpleDateFormat("HH:mm MMM d yyyy", Locale.ENGLISH);
position.setTime(dateFormat.parse(matcher.group(1) + " " + Calendar.getInstance().get(Calendar.YEAR)));
+
return position;
}
diff --git a/src/org/traccar/protocol/MaxonProtocol.java b/src/org/traccar/protocol/TrvProtocol.java
index 587c3f014..916b7d612 100644
--- a/src/org/traccar/protocol/MaxonProtocol.java
+++ b/src/org/traccar/protocol/TrvProtocol.java
@@ -17,18 +17,18 @@ package org.traccar.protocol;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.handler.codec.frame.LineBasedFrameDecoder;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
+import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.TrackerServer;
import java.util.List;
-public class MaxonProtocol extends BaseProtocol {
+public class TrvProtocol extends BaseProtocol {
- public MaxonProtocol() {
- super("maxon");
+ public TrvProtocol() {
+ super("trv");
}
@Override
@@ -36,10 +36,10 @@ public class MaxonProtocol extends BaseProtocol {
serverList.add(new TrackerServer(new ServerBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
+ pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, '#'));
pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
- pipeline.addLast("objectDecoder", new MaxonProtocolDecoder(MaxonProtocol.this));
+ pipeline.addLast("objectDecoder", new TrvProtocolDecoder(TrvProtocol.this));
}
});
}
diff --git a/src/org/traccar/protocol/TrvProtocolDecoder.java b/src/org/traccar/protocol/TrvProtocolDecoder.java
new file mode 100644
index 000000000..fe1162d24
--- /dev/null
+++ b/src/org/traccar/protocol/TrvProtocolDecoder.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2015 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 TrvProtocolDecoder extends BaseProtocolDecoder {
+
+ public TrvProtocolDecoder(TrvProtocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("TRV")
+ .number("APdd")
+ .number("(dd)(dd)(dd)") // date
+ .expression("([AV])") // validity
+ .number("(dd)(dd.d+)") // latitude
+ .expression("([NS])")
+ .number("(ddd)(dd.d+)") // longitude
+ .expression("([EW])")
+ .number("(ddd.d)") // speed
+ .number("(dd)(dd)(dd)") // time
+ .number("(ddd.dd)") // course
+ .number("(ddd)") // gsm
+ .number("(ddd)") // satellites
+ .number("(ddd)") // battery
+ .number("(d)") // acc
+ .number("dd") // arm status
+ .number("dd,") // working mode
+ .number("(d+),") // mcc
+ .number("(d+),") // mnc
+ .number("(d+),") // lac
+ .number("(d+)") // cell
+ .any()
+ .compile();
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ String sentence = (String) msg;
+
+ String type = sentence.substring(3, 7);
+ if (channel != null) {
+ channel.write("B" + type.substring(1)); // response
+ }
+
+ if (type.equals("AP00")) {
+ identify(sentence.substring(7), channel);
+ return null;
+ }
+
+ if (!hasDeviceId()) {
+ return null;
+ }
+
+ if (type.equals("AP01") || type.equals("AP10")) {
+
+ Parser parser = new Parser(PATTERN, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(getDeviceId());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt());
+
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+
+ dateBuilder.setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+
+ position.setCourse(parser.nextDouble());
+
+ position.set(Event.KEY_GSM, parser.nextInt());
+ position.set(Event.KEY_SATELLITES, parser.nextInt());
+ position.set(Event.KEY_BATTERY, parser.nextInt());
+
+ int acc = parser.nextInt();
+ if (acc != 0) {
+ position.set(Event.KEY_IGNITION, acc == 1);
+ }
+
+ position.set(Event.KEY_MCC, parser.nextInt());
+ position.set(Event.KEY_MNC, parser.nextInt());
+ position.set(Event.KEY_LAC, parser.nextInt());
+ position.set(Event.KEY_CELL, parser.nextInt());
+
+ return position;
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/protocol/UlbotechProtocolDecoder.java b/src/org/traccar/protocol/UlbotechProtocolDecoder.java
index b015e768a..68d04906d 100644
--- a/src/org/traccar/protocol/UlbotechProtocolDecoder.java
+++ b/src/org/traccar/protocol/UlbotechProtocolDecoder.java
@@ -24,6 +24,7 @@ import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.Context;
import org.traccar.helper.BitUtil;
+import org.traccar.helper.ObdDecoder;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -58,10 +59,9 @@ public class UlbotechProtocolDecoder extends BaseProtocolDecoder {
int end = buf.readerIndex() + length;
while (buf.readerIndex() < end) {
- int parameterLength = buf.readUnsignedByte() >> 4;
- String key = String.format("pid%02X", buf.readUnsignedByte());
- String value = ChannelBuffers.hexDump(buf.readBytes(parameterLength - 2));
- position.set(key, value);
+ int parameterLength = buf.getUnsignedByte(buf.readerIndex()) >> 4;
+ position.add(ObdDecoder.decode(buf.readUnsignedByte() & 0x0F, buf.readUnsignedByte(),
+ ChannelBuffers.hexDump(buf.readBytes(parameterLength - 2))));
}
}
@@ -105,18 +105,15 @@ public class UlbotechProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedByte(); // version
buf.readUnsignedByte(); // type
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- // Get device id
String imei = ChannelBuffers.hexDump(buf.readBytes(8)).substring(1);
if (!identify(imei, channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Time
long seconds = buf.readUnsignedInt() & 0x7fffffffL;
seconds += 946684800L; // 2000-01-01 00:00
seconds -= timeZone;
@@ -197,7 +194,7 @@ public class UlbotechProtocolDecoder extends BaseProtocolDecoder {
break;
case DATA_VIN:
- position.set("vin", buf.readBytes(length).toString(Charset.defaultCharset()));
+ position.set(Event.KEY_VIN, buf.readBytes(length).toString(Charset.defaultCharset()));
break;
case DATA_RFID:
diff --git a/src/org/traccar/protocol/VisiontekProtocolDecoder.java b/src/org/traccar/protocol/VisiontekProtocolDecoder.java
index 8dc4bdf06..2fecda341 100644
--- a/src/org/traccar/protocol/VisiontekProtocolDecoder.java
+++ b/src/org/traccar/protocol/VisiontekProtocolDecoder.java
@@ -19,7 +19,10 @@ import java.net.SocketAddress;
import java.util.regex.Pattern;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.helper.*;
+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;
diff --git a/src/org/traccar/protocol/Ev603Protocol.java b/src/org/traccar/protocol/WatchProtocol.java
index 8e00b534f..3a10f9c59 100644
--- a/src/org/traccar/protocol/Ev603Protocol.java
+++ b/src/org/traccar/protocol/WatchProtocol.java
@@ -18,16 +18,17 @@ 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.jboss.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.TrackerServer;
import java.util.List;
-public class Ev603Protocol extends BaseProtocol {
+public class WatchProtocol extends BaseProtocol {
- public Ev603Protocol() {
- super("ev603");
+ public WatchProtocol() {
+ super("watch");
}
@Override
@@ -35,9 +36,10 @@ public class Ev603Protocol extends BaseProtocol {
serverList.add(new TrackerServer(new ServerBootstrap(), this.getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, ';'));
+ pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, ']'));
pipeline.addLast("stringDecoder", new StringDecoder());
- pipeline.addLast("objectDecoder", new Ev603ProtocolDecoder(Ev603Protocol.this));
+ pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("objectDecoder", new WatchProtocolDecoder(WatchProtocol.this));
}
});
}
diff --git a/src/org/traccar/protocol/WatchProtocolDecoder.java b/src/org/traccar/protocol/WatchProtocolDecoder.java
new file mode 100644
index 000000000..a24d0a56b
--- /dev/null
+++ b/src/org/traccar/protocol/WatchProtocolDecoder.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2015 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 WatchProtocolDecoder extends BaseProtocolDecoder {
+
+ public WatchProtocolDecoder(WatchProtocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("[")
+ .expression("(..)").text("*") // manufacturer
+ .number("(d+)").text("*") // equipment id
+ .number("xxxx").text("*") // length
+ .expression("([^,]+)") // type
+ .expression("(.*)") // content
+ .compile();
+
+ private static final Pattern PATTERN_POSITION = new PatternBuilder()
+ .text(",")
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .number("(dd)(dd)(dd),") // time
+ .expression("([AV]),") // validity
+ .number("(d+.d+),") // latitude
+ .expression("([NS]),")
+ .number("(d+.d+),") // longitude
+ .expression("([EW]),")
+ .number("(d+.d+),") // speed
+ .number("(d+.d+),") // course
+ .number("(d+.?d*),") // altitude
+ .number("(d+),") // satellites
+ .number("(d+),") // gsm
+ .number("(d+),") // battery
+ .number("(d+),") // steps
+ .number("d+,") // tumbles
+ .any()
+ .compile();
+
+ private void sendResponse(Channel channel, String manufacturer, String id, String content) {
+ if (channel != null) {
+ channel.write(
+ String.format("[%s*%s*%04x*%s]", manufacturer, id, content.length(), content));
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ Parser parser = new Parser(PATTERN, (String) msg);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ String manufacturer = parser.next();
+ String id = parser.next();
+ if (!identify(id, channel)) {
+ return null;
+ }
+
+ String type = parser.next();
+ String content = parser.next();
+
+ if (type.equals("LK")) {
+
+ sendResponse(channel, manufacturer, id, "LK");
+
+ if (!content.isEmpty()) {
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(getDeviceId());
+
+ getLastLocation(position, null);
+
+ position.set(Event.KEY_BATTERY, content.split(",")[3]);
+
+ return position;
+ }
+
+ } else if (type.equals("UD") || type.equals("UD2") || type.equals("AL")) {
+
+ if (type.equals("AL")) {
+ sendResponse(channel, manufacturer, id, "AL");
+ }
+
+ parser = new Parser(PATTERN_POSITION, content);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(getDeviceId());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
+ position.setAltitude(parser.nextDouble());
+
+ position.set(Event.KEY_SATELLITES, parser.nextInt());
+ position.set(Event.KEY_GSM, parser.nextInt());
+ position.set(Event.KEY_BATTERY, parser.nextInt());
+
+ position.set("steps", parser.nextInt());
+
+ return position;
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/protocol/WondexProtocolDecoder.java b/src/org/traccar/protocol/WondexProtocolDecoder.java
index c2a5a2201..1a639b05c 100644
--- a/src/org/traccar/protocol/WondexProtocolDecoder.java
+++ b/src/org/traccar/protocol/WondexProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2013 - 2015 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,12 +16,12 @@
package org.traccar.protocol;
import java.net.SocketAddress;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
@@ -32,88 +32,67 @@ public class WondexProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = Pattern.compile(
- "[^\\d]*" + // Header
- "(\\d+)," + // Device Identifier
- "(\\d{4})(\\d{2})(\\d{2})" + // Date (YYYYMMDD)
- "(\\d{2})(\\d{2})(\\d{2})," + // Time (HHMMSS)
- "(-?\\d+\\.\\d+)," + // Longitude
- "(-?\\d+\\.\\d+)," + // Latitude
- "(\\d+)," + // Speed
- "(\\d+)," + // Course
- "(-?\\d+\\.?\\d*)," + // Altitude
- "(\\d+)," + // Satellites
- "(\\d+),?" + // Event
- "(?:(\\d+\\.\\d+)V,)?" + // Battery
- "(\\d+\\.\\d+)?,?" + // Odometer
- "(\\d+)?,?" + // Input
- "(\\d+\\.\\d+)?,?" + // ADC1
- "(\\d+\\.\\d+)?,?" + // ADC2
- "(\\d+)?.*"); // Output
+ private static final Pattern PATTERN = new PatternBuilder()
+ .number("[^d]*") // deader
+ .number("(d+),") // device identifier
+ .number("(dddd)(dd)(dd)") // date
+ .number("(dd)(dd)(dd),") // time
+ .number("(-?d+.d+),") // longitude
+ .number("(-?d+.d+),") // latitude
+ .number("(d+),") // speed
+ .number("(d+),") // course
+ .number("(-?d+.?d*),") // altitude
+ .number("(d+),") // satellites
+ .number("(d+),?") // event
+ .number("(d+.d+)V,").optional() // battery
+ .number("(d+.d+)?,?") // odometer
+ .number("(d+)?,?") // input
+ .number("(d+.d+)?,?") // adc1
+ .number("(d+.d+)?,?") // adc2
+ .number("(d+)?") // output
+ .any()
+ .compile();
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg)
- throws Exception {
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- // Parse message
- Matcher parser = PATTERN.matcher((String) msg);
+ Parser parser = new Parser(PATTERN, (String) msg);
if (!parser.matches()) {
return null;
}
- // Create new position
Position position = new Position();
position.setProtocol(getProtocolName());
- int index = 1;
- // Device identifier
- if (!identify(parser.group(index++), channel)) {
+ if (!identify(parser.next(), channel)) {
return null;
}
position.setDeviceId(getDeviceId());
- // Time
- Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- time.clear();
- time.set(Calendar.YEAR, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MONTH, Integer.parseInt(parser.group(index++)) - 1);
- time.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.MINUTE, Integer.parseInt(parser.group(index++)));
- time.set(Calendar.SECOND, Integer.parseInt(parser.group(index++)));
- position.setTime(time.getTime());
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt())
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
- // Position data
- position.setLongitude(Double.parseDouble(parser.group(index++)));
- position.setLatitude(Double.parseDouble(parser.group(index++)));
- position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(parser.group(index++))));
- position.setCourse(Double.parseDouble(parser.group(index++)));
- position.setAltitude(Double.parseDouble(parser.group(index++)));
+ position.setLongitude(parser.nextDouble());
+ position.setLatitude(parser.nextDouble());
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
+ position.setAltitude(parser.nextDouble());
- // Satellites
- int satellites = Integer.parseInt(parser.group(index++));
+ int satellites = parser.nextInt();
position.setValid(satellites >= 3);
position.set(Event.KEY_SATELLITES, satellites);
- // Event
- position.set(Event.KEY_EVENT, parser.group(index++));
+ position.set(Event.KEY_EVENT, parser.next());
+ position.set(Event.KEY_BATTERY, parser.next());
+ position.set(Event.KEY_ODOMETER, parser.next());
+ position.set(Event.KEY_INPUT, parser.next());
+ position.set(Event.PREFIX_ADC + 1, parser.next());
+ position.set(Event.PREFIX_ADC + 2, parser.next());
+ position.set(Event.KEY_OUTPUT, parser.next());
- // Battery
- position.set(Event.KEY_BATTERY, parser.group(index++));
-
- // Odometer
- position.set(Event.KEY_ODOMETER, parser.group(index++));
-
- // Input
- position.set(Event.KEY_INPUT, parser.group(index++));
-
- // ADC
- position.set(Event.PREFIX_ADC + 1, parser.group(index++));
- position.set(Event.PREFIX_ADC + 2, parser.group(index++));
-
- // Output
- position.set(Event.KEY_OUTPUT, parser.group(index++));
return position;
}
diff --git a/src/org/traccar/web/AsyncServlet.java b/src/org/traccar/web/AsyncServlet.java
index 73803ab91..63b08ff3e 100644
--- a/src/org/traccar/web/AsyncServlet.java
+++ b/src/org/traccar/web/AsyncServlet.java
@@ -50,7 +50,7 @@ public class AsyncServlet extends BaseServlet {
public static class AsyncSession {
- private static final boolean DEBUG_ASYNC = false;
+ private static final boolean DEBUG_ASYNC = true;
private static final long SESSION_TIMEOUT = 30;
private static final long REQUEST_TIMEOUT = 20;
@@ -88,7 +88,7 @@ public class AsyncServlet extends BaseServlet {
private final ConnectionManager.DataCacheListener dataListener = new ConnectionManager.DataCacheListener() {
@Override
- public void onUpdate(Position position) {
+ public void onUpdatePosition(Position position) {
synchronized (AsyncSession.this) {
logEvent("onUpdate deviceId: " + position.getDeviceId());
if (!destroyed) {
@@ -114,7 +114,9 @@ public class AsyncServlet extends BaseServlet {
}
Context.getConnectionManager().removeListener(devices, dataListener);
synchronized (ASYNC_SESSIONS) {
- ASYNC_SESSIONS.remove(userId);
+ if (ASYNC_SESSIONS.get(userId) == AsyncSession.this) {
+ ASYNC_SESSIONS.remove(userId);
+ }
}
}
};