diff options
223 files changed, 6135 insertions, 5066 deletions
@@ -63,8 +63,8 @@ language VARCHAR(128), distanceUnit VARCHAR(128), speedUnit VARCHAR(128), - latitude FLOAT DEFAULT 0 NOT NULL, - longitude FLOAT DEFAULT 0 NOT NULL, + latitude DOUBLE PRECISION DEFAULT 0 NOT NULL, + longitude DOUBLE PRECISION DEFAULT 0 NOT NULL, zoom INT DEFAULT 0 NOT NULL); CREATE TABLE device ( @@ -93,8 +93,8 @@ deviceTime TIMESTAMP NOT NULL, fixTime TIMESTAMP NOT NULL, valid BIT NOT NULL, - latitude FLOAT NOT NULL, - longitude FLOAT NOT NULL, + latitude DOUBLE PRECISION NOT NULL, + longitude DOUBLE PRECISION NOT NULL, altitude FLOAT NOT NULL, speed FLOAT NOT NULL, course FLOAT NOT NULL, @@ -113,14 +113,14 @@ language VARCHAR(128), distanceUnit VARCHAR(128), speedUnit VARCHAR(128), - latitude FLOAT DEFAULT 0 NOT NULL, - longitude FLOAT DEFAULT 0 NOT NULL, + latitude DOUBLE PRECISION DEFAULT 0 NOT NULL, + longitude DOUBLE PRECISION DEFAULT 0 NOT NULL, zoom INT DEFAULT 0 NOT NULL); CREATE TABLE traccar ( version INT DEFAULT 0 NOT NULL); - INSERT INTO traccar (version) VALUES (301); + INSERT INTO traccar (version) VALUES (302); </entry> <entry key='database.selectServers'> @@ -251,12 +251,12 @@ <entry key='totem.port'>5007</entry> <entry key='enfora.port'>5008</entry> <entry key='meiligao.port'>5009</entry> - <entry key='maxon.port'>5010</entry> + <entry key='trv.port'>5010</entry> <entry key='suntech.port'>5011</entry> <entry key='progress.port'>5012</entry> <entry key='h02.port'>5013</entry> <entry key='jt600.port'>5014</entry> - <entry key='ev603.port'>5015</entry> + <entry key='huabao.port'>5015</entry> <entry key='v680.port'>5016</entry> <entry key='pt502.port'>5017</entry> <entry key='tr20.port'>5018</entry> @@ -334,5 +334,7 @@ <entry key='flextrack.port'>5090</entry> <entry key='blackkite.port'>5091</entry> <entry key='adm.port'>5092</entry> + <entry key='watch.port'>5093</entry> + <entry key='t800x.port'>5094</entry> </properties> @@ -4,14 +4,14 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.traccar</groupId> <artifactId>traccar</artifactId> - <version>3.1-SNAPSHOT</version> + <version>3.2-SNAPSHOT</version> <name>traccar</name> <url>https://www.traccar.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <jetty.version>9.2.13.v20150730</jetty.version> + <jetty.version>9.2.14.v20151106</jetty.version> <!-- Jetty 9.3+ requires Java 8 --> </properties> <dependencies> @@ -29,22 +29,22 @@ <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> - <version>2.8.1</version> + <version>2.9.1</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> - <version>1.4.187</version> + <version>1.4.190</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> - <version>5.1.36</version> + <version>5.1.37</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> - <version>9.4-1201-jdbc41</version> + <version>9.4-1205-jdbc41</version> </dependency> <dependency> <groupId>com.mchange</groupId> @@ -54,25 +54,23 @@ <dependency> <groupId>io.netty</groupId> <artifactId>netty</artifactId> - <version>3.10.4.Final</version> + <version>3.10.5.Final</version> </dependency> <dependency> - <groupId>com.ning</groupId> + <groupId>com.ning</groupId> <!-- org.asynchttpclient starting from version 2.0 --> <artifactId>async-http-client</artifactId> - <version>1.9.30</version> + <version>1.9.31</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> - <version>1.7.12</version> + <version>1.7.13</version> </dependency> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.json</artifactId> <version>1.0.4</version> </dependency> - - <!-- Jetty 9.3+ requires Java 8 --> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> @@ -154,7 +152,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> - <version>2.5.5</version> + <version>2.6</version> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> @@ -196,7 +194,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-checkstyle-plugin</artifactId> - <version>2.16</version> + <version>2.17</version> <configuration> <configLocation>checkstyle.xml</configLocation> </configuration> @@ -204,7 +202,7 @@ <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> - <version>3.0.2</version> + <version>3.0.3</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> diff --git a/setup/package.sh b/setup/package.sh index b8b35235b..bd6fa6950 100755 --- a/setup/package.sh +++ b/setup/package.sh @@ -54,10 +54,10 @@ cleanup () { prepare_windows_64 () { unzip wrapper-windows-x86-64-*.zip - cp wrapper_*_src/bin/wrapper.exe wrapper/bin/wrapper-windows-x86-32.exe - cp wrapper_*_src/lib/wrapper.dll wrapper/lib/wrapper-windows-x86-32.dll - cp wrapper_*_src/lib/wrapper.jar wrapper/lib/wrapper.jar - rm -rf wrapper_*_src + cp wrapper-windows-*/bin/wrapper.exe wrapper/bin/wrapper-windows-x86-32.exe + cp wrapper-windows-*/lib/wrapper.dll wrapper/lib/wrapper-windows-x86-32.dll + cp wrapper-windows-*/lib/wrapper.jar wrapper/lib/wrapper.jar + rm -rf wrapper-windows-*/ } prepare_linux_32 () { diff --git a/setup/unix/traccar.xml b/setup/unix/traccar.xml index 70270b7d1..eb4321bd2 100644 --- a/setup/unix/traccar.xml +++ b/setup/unix/traccar.xml @@ -43,8 +43,8 @@ language VARCHAR(128), distanceUnit VARCHAR(128), speedUnit VARCHAR(128), - latitude FLOAT DEFAULT 0 NOT NULL, - longitude FLOAT DEFAULT 0 NOT NULL, + latitude DOUBLE PRECISION DEFAULT 0 NOT NULL, + longitude DOUBLE PRECISION DEFAULT 0 NOT NULL, zoom INT DEFAULT 0 NOT NULL); CREATE TABLE device ( @@ -53,8 +53,7 @@ uniqueId VARCHAR(128) NOT NULL UNIQUE, status VARCHAR(128), lastUpdate TIMESTAMP, - positionId INT, - dataId INT); + positionId INT); CREATE TABLE user_device ( userId INT NOT NULL, @@ -74,47 +73,34 @@ deviceTime TIMESTAMP NOT NULL, fixTime TIMESTAMP NOT NULL, valid BIT NOT NULL, - latitude FLOAT NOT NULL, - longitude FLOAT NOT NULL, + latitude DOUBLE PRECISION NOT NULL, + longitude DOUBLE PRECISION NOT NULL, altitude FLOAT NOT NULL, speed FLOAT NOT NULL, course FLOAT NOT NULL, address VARCHAR(512), - other VARCHAR(4096) NOT NULL, - FOREIGN KEY (deviceId) REFERENCES device (id) ON DELETE CASCADE); - - CREATE INDEX position_deviceId_fixTime ON position (deviceId, fixTime); - - CREATE TABLE data ( - id INT PRIMARY KEY AUTO_INCREMENT, - protocol VARCHAR(128), - deviceId INT NOT NULL, - serverTime TIMESTAMP NOT NULL, - deviceTime TIMESTAMP NOT NULL, - other VARCHAR(4096) NOT NULL, + attributes VARCHAR(4096) NOT NULL, FOREIGN KEY (deviceId) REFERENCES device (id) ON DELETE CASCADE); - ALTER TABLE device ADD - FOREIGN KEY (positionId) REFERENCES position (id) ON DELETE CASCADE; - - ALTER TABLE device ADD - FOREIGN KEY (dataId) REFERENCES data (id) ON DELETE CASCADE; + CREATE INDEX position_deviceId_fixTime ON position (deviceId, fixTime); CREATE TABLE server ( id INT PRIMARY KEY AUTO_INCREMENT, registration BIT NOT NULL, map VARCHAR(128), + bingKey VARCHAR(128), + mapUrl VARCHAR(128), language VARCHAR(128), distanceUnit VARCHAR(128), speedUnit VARCHAR(128), - latitude FLOAT DEFAULT 0 NOT NULL, - longitude FLOAT DEFAULT 0 NOT NULL, + latitude DOUBLE PRECISION DEFAULT 0 NOT NULL, + longitude DOUBLE PRECISION DEFAULT 0 NOT NULL, zoom INT DEFAULT 0 NOT NULL); CREATE TABLE traccar ( version INT DEFAULT 0 NOT NULL); - INSERT INTO traccar (version) VALUES (301); + INSERT INTO traccar (version) VALUES (302); </entry> <entry key='database.selectServers'> @@ -130,6 +116,8 @@ UPDATE server SET registration = :registration, map = :map, + bingKey = :bingKey, + mapUrl = :mapUrl, language = :language, distanceUnit = :distanceUnit, speedUnit = :speedUnit, @@ -176,7 +164,7 @@ <entry key='database.updateUserPassword'> UPDATE "user" SET hashedPassword = :hashedPassword, salt = :salt WHERE id = :id; </entry> - + <entry key='database.deleteUser'> DELETE FROM "user" WHERE id = :id; </entry> @@ -184,38 +172,42 @@ <entry key='database.getPermissionsAll'> SELECT userId, deviceId FROM user_device; </entry> - + <entry key='database.selectDevicesAll'> SELECT * FROM device; </entry> - + <entry key='database.selectDevices'> SELECT * FROM device d INNER JOIN user_device ud ON d.id = ud.deviceId WHERE ud.userId = :userId; </entry> - + <entry key='database.insertDevice'> INSERT INTO device (name, uniqueId) VALUES (:name, :uniqueId); </entry> - + <entry key='database.updateDevice'> UPDATE device SET name = :name, uniqueId = :uniqueId WHERE id = :id; </entry> - + <entry key='database.deleteDevice'> DELETE FROM device WHERE id = :id; </entry> - + <entry key='database.linkDevice'> INSERT INTO user_device (userId, deviceId) VALUES (:userId, :deviceId); </entry> + <entry key='database.unlinkDevice'> + DELETE FROM user_device WHERE userId = :userId AND deviceId = :deviceId; + </entry> + <entry key='database.selectPositions'> - SELECT * FROM position WHERE deviceId = :deviceId AND fixTime BETWEEN :from AND :to; + SELECT * FROM position WHERE deviceId = :deviceId AND fixTime BETWEEN :from AND :to ORDER BY fixTime; </entry> <entry key='database.insertPosition'> - INSERT INTO position (deviceId, protocol, serverTime, deviceTime, fixTime, valid, latitude, longitude, altitude, speed, course, address, other) - VALUES (:deviceId, :protocol, CURRENT_TIMESTAMP(), :time, :time, :valid, :latitude, :longitude, :altitude, :speed, :course, :address, :other); + INSERT INTO position (deviceId, protocol, serverTime, deviceTime, fixTime, valid, latitude, longitude, altitude, speed, course, address, attributes) + VALUES (:deviceId, :protocol, CURRENT_TIMESTAMP(), :time, :time, :valid, :latitude, :longitude, :altitude, :speed, :course, :address, :attributes); </entry> <entry key='database.selectLatestPositions'> @@ -238,12 +230,12 @@ <entry key='totem.port'>5007</entry> <entry key='enfora.port'>5008</entry> <entry key='meiligao.port'>5009</entry> - <entry key='maxon.port'>5010</entry> + <entry key='trv.port'>5010</entry> <entry key='suntech.port'>5011</entry> <entry key='progress.port'>5012</entry> <entry key='h02.port'>5013</entry> <entry key='jt600.port'>5014</entry> - <entry key='ev603.port'>5015</entry> + <entry key='huabao.port'>5015</entry> <entry key='v680.port'>5016</entry> <entry key='pt502.port'>5017</entry> <entry key='tr20.port'>5018</entry> @@ -266,7 +258,7 @@ <entry key='ywt.port'>5035</entry> <entry key='tk102.port'>5036</entry> <entry key='intellitrac.port'>5037</entry> - <entry key='xt7.port'>5038</entry> + <entry key='gpsmta.port'>5038</entry> <entry key='wialon.port'>5039</entry> <entry key='carscop.port'>5040</entry> <entry key='apel.port'>5041</entry> @@ -317,5 +309,11 @@ <entry key='castel.port'>5086</entry> <entry key='mxt.port'>5087</entry> <entry key='cityeasy.port'>5088</entry> + <entry key='aquila.port'>5089</entry> + <entry key='flextrack.port'>5090</entry> + <entry key='blackkite.port'>5091</entry> + <entry key='adm.port'>5092</entry> + <entry key='watch.port'>5093</entry> + <entry key='t800x.port'>5094</entry> </properties> diff --git a/setup/windows/traccar.iss b/setup/windows/traccar.iss index 2c0dac5e6..7a21059ad 100644 --- a/setup/windows/traccar.iss +++ b/setup/windows/traccar.iss @@ -1,6 +1,6 @@ [Setup]
AppName=Traccar
-AppVersion=3.1
+AppVersion=3.2
DefaultDirName={pf}\Traccar
AlwaysRestart=yes
diff --git a/setup/windows/traccar.xml b/setup/windows/traccar.xml index bf0dc3efa..419299a04 100644 --- a/setup/windows/traccar.xml +++ b/setup/windows/traccar.xml @@ -43,8 +43,8 @@ language VARCHAR(128),
distanceUnit VARCHAR(128),
speedUnit VARCHAR(128),
- latitude FLOAT DEFAULT 0 NOT NULL,
- longitude FLOAT DEFAULT 0 NOT NULL,
+ latitude DOUBLE PRECISION DEFAULT 0 NOT NULL,
+ longitude DOUBLE PRECISION DEFAULT 0 NOT NULL,
zoom INT DEFAULT 0 NOT NULL);
CREATE TABLE device (
@@ -53,8 +53,7 @@ uniqueId VARCHAR(128) NOT NULL UNIQUE,
status VARCHAR(128),
lastUpdate TIMESTAMP,
- positionId INT,
- dataId INT);
+ positionId INT);
CREATE TABLE user_device (
userId INT NOT NULL,
@@ -74,47 +73,34 @@ deviceTime TIMESTAMP NOT NULL,
fixTime TIMESTAMP NOT NULL,
valid BIT NOT NULL,
- latitude FLOAT NOT NULL,
- longitude FLOAT NOT NULL,
+ latitude DOUBLE PRECISION NOT NULL,
+ longitude DOUBLE PRECISION NOT NULL,
altitude FLOAT NOT NULL,
speed FLOAT NOT NULL,
course FLOAT NOT NULL,
address VARCHAR(512),
- other VARCHAR(4096) NOT NULL,
- FOREIGN KEY (deviceId) REFERENCES device (id) ON DELETE CASCADE);
-
- CREATE INDEX position_deviceId_fixTime ON position (deviceId, fixTime);
-
- CREATE TABLE data (
- id INT PRIMARY KEY AUTO_INCREMENT,
- protocol VARCHAR(128),
- deviceId INT NOT NULL,
- serverTime TIMESTAMP NOT NULL,
- deviceTime TIMESTAMP NOT NULL,
- other VARCHAR(4096) NOT NULL,
+ attributes VARCHAR(4096) NOT NULL,
FOREIGN KEY (deviceId) REFERENCES device (id) ON DELETE CASCADE);
- ALTER TABLE device ADD
- FOREIGN KEY (positionId) REFERENCES position (id) ON DELETE CASCADE;
-
- ALTER TABLE device ADD
- FOREIGN KEY (dataId) REFERENCES data (id) ON DELETE CASCADE;
+ CREATE INDEX position_deviceId_fixTime ON position (deviceId, fixTime);
CREATE TABLE server (
id INT PRIMARY KEY AUTO_INCREMENT,
registration BIT NOT NULL,
map VARCHAR(128),
+ bingKey VARCHAR(128),
+ mapUrl VARCHAR(128),
language VARCHAR(128),
distanceUnit VARCHAR(128),
speedUnit VARCHAR(128),
- latitude FLOAT DEFAULT 0 NOT NULL,
- longitude FLOAT DEFAULT 0 NOT NULL,
+ latitude DOUBLE PRECISION DEFAULT 0 NOT NULL,
+ longitude DOUBLE PRECISION DEFAULT 0 NOT NULL,
zoom INT DEFAULT 0 NOT NULL);
CREATE TABLE traccar (
version INT DEFAULT 0 NOT NULL);
- INSERT INTO traccar (version) VALUES (301);
+ INSERT INTO traccar (version) VALUES (302);
</entry>
<entry key='database.selectServers'>
@@ -130,6 +116,8 @@ UPDATE server SET
registration = :registration,
map = :map,
+ bingKey = :bingKey,
+ mapUrl = :mapUrl,
language = :language,
distanceUnit = :distanceUnit,
speedUnit = :speedUnit,
@@ -176,7 +164,7 @@ <entry key='database.updateUserPassword'>
UPDATE "user" SET hashedPassword = :hashedPassword, salt = :salt WHERE id = :id;
</entry>
-
+
<entry key='database.deleteUser'>
DELETE FROM "user" WHERE id = :id;
</entry>
@@ -184,38 +172,42 @@ <entry key='database.getPermissionsAll'>
SELECT userId, deviceId FROM user_device;
</entry>
-
+
<entry key='database.selectDevicesAll'>
SELECT * FROM device;
</entry>
-
+
<entry key='database.selectDevices'>
SELECT * FROM device d INNER JOIN user_device ud ON d.id = ud.deviceId WHERE ud.userId = :userId;
</entry>
-
+
<entry key='database.insertDevice'>
INSERT INTO device (name, uniqueId) VALUES (:name, :uniqueId);
</entry>
-
+
<entry key='database.updateDevice'>
UPDATE device SET name = :name, uniqueId = :uniqueId WHERE id = :id;
</entry>
-
+
<entry key='database.deleteDevice'>
DELETE FROM device WHERE id = :id;
</entry>
-
+
<entry key='database.linkDevice'>
INSERT INTO user_device (userId, deviceId) VALUES (:userId, :deviceId);
</entry>
+ <entry key='database.unlinkDevice'>
+ DELETE FROM user_device WHERE userId = :userId AND deviceId = :deviceId;
+ </entry>
+
<entry key='database.selectPositions'>
- SELECT * FROM position WHERE deviceId = :deviceId AND fixTime BETWEEN :from AND :to;
+ SELECT * FROM position WHERE deviceId = :deviceId AND fixTime BETWEEN :from AND :to ORDER BY fixTime;
</entry>
<entry key='database.insertPosition'>
- INSERT INTO position (deviceId, protocol, serverTime, deviceTime, fixTime, valid, latitude, longitude, altitude, speed, course, address, other)
- VALUES (:deviceId, :protocol, CURRENT_TIMESTAMP(), :time, :time, :valid, :latitude, :longitude, :altitude, :speed, :course, :address, :other);
+ INSERT INTO position (deviceId, protocol, serverTime, deviceTime, fixTime, valid, latitude, longitude, altitude, speed, course, address, attributes)
+ VALUES (:deviceId, :protocol, CURRENT_TIMESTAMP(), :time, :time, :valid, :latitude, :longitude, :altitude, :speed, :course, :address, :attributes);
</entry>
<entry key='database.selectLatestPositions'>
@@ -238,12 +230,12 @@ <entry key='totem.port'>5007</entry>
<entry key='enfora.port'>5008</entry>
<entry key='meiligao.port'>5009</entry>
- <entry key='maxon.port'>5010</entry>
+ <entry key='trv.port'>5010</entry>
<entry key='suntech.port'>5011</entry>
<entry key='progress.port'>5012</entry>
<entry key='h02.port'>5013</entry>
<entry key='jt600.port'>5014</entry>
- <entry key='ev603.port'>5015</entry>
+ <entry key='huabao.port'>5015</entry>
<entry key='v680.port'>5016</entry>
<entry key='pt502.port'>5017</entry>
<entry key='tr20.port'>5018</entry>
@@ -266,7 +258,7 @@ <entry key='ywt.port'>5035</entry>
<entry key='tk102.port'>5036</entry>
<entry key='intellitrac.port'>5037</entry>
- <entry key='xt7.port'>5038</entry>
+ <entry key='gpsmta.port'>5038</entry>
<entry key='wialon.port'>5039</entry>
<entry key='carscop.port'>5040</entry>
<entry key='apel.port'>5041</entry>
@@ -317,5 +309,11 @@ <entry key='castel.port'>5086</entry>
<entry key='mxt.port'>5087</entry>
<entry key='cityeasy.port'>5088</entry>
+ <entry key='aquila.port'>5089</entry>
+ <entry key='flextrack.port'>5090</entry>
+ <entry key='blackkite.port'>5091</entry>
+ <entry key='adm.port'>5092</entry>
+ <entry key='watch.port'>5093</entry>
+ <entry key='t800x.port'>5094</entry>
</properties>
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); + } } } }; diff --git a/test/org/traccar/ProtocolDecoderTest.java b/test/org/traccar/ProtocolDecoderTest.java index e52ea4695..133b0229f 100644 --- a/test/org/traccar/ProtocolDecoderTest.java +++ b/test/org/traccar/ProtocolDecoderTest.java @@ -38,7 +38,7 @@ public class ProtocolDecoderTest { } @Override - public Device getDeviceByUniqueId(String imei) { + public Device getDeviceByUniqueId(String uniqueId) { return createDevice(); } @@ -67,8 +67,8 @@ public class ProtocolDecoderTest { protected void verifyPositions(BaseProtocolDecoder decoder, Object object) throws Exception { Object decodedObject = decoder.decode(null, null, object); - Assert.assertNotNull(decodedObject); - Assert.assertTrue(decodedObject instanceof List); + Assert.assertNotNull("list is null", decodedObject); + Assert.assertTrue("not a list", decodedObject instanceof List); Assert.assertFalse("list if empty", ((List) decodedObject).isEmpty()); for (Object item : (List) decodedObject) { verifyDecodedPosition(item); @@ -77,8 +77,8 @@ public class ProtocolDecoderTest { protected void verifyPositions(BaseProtocolDecoder decoder, Object object, Position position) throws Exception { Object decodedObject = decoder.decode(null, null, object); - Assert.assertNotNull(decodedObject); - Assert.assertTrue(decodedObject instanceof List); + Assert.assertNotNull("list is null", decodedObject); + Assert.assertTrue("not a list", decodedObject instanceof List); Assert.assertFalse("list if empty", ((List) decodedObject).isEmpty()); for (Object item : (List) decodedObject) { verifyDecodedPosition(item, position); @@ -154,6 +154,17 @@ public class ProtocolDecoderTest { Assert.assertEquals("latitude", expected.getLatitude(), position.getLatitude(), 0.00001); Assert.assertEquals("longitude", expected.getLongitude(), position.getLongitude(), 0.00001); + Assert.assertTrue("altitude >= -12262", position.getAltitude() >= -12262); + Assert.assertTrue("altitude <= 18000", position.getAltitude() <= 18000); + + Assert.assertTrue("speed >= 0", position.getSpeed() >= 0); + Assert.assertTrue("speed <= 869", position.getSpeed() <= 869); + + Assert.assertTrue("course >= 0", position.getCourse() >= 0); + Assert.assertTrue("course <= 360", position.getCourse() <= 360); + + Assert.assertNotNull("protocol is null", position.getProtocol()); + } private void verifyDecodedPosition(Object decodedObject) { @@ -183,6 +194,8 @@ public class ProtocolDecoderTest { Assert.assertTrue("course >= 0", position.getCourse() >= 0); Assert.assertTrue("course <= 360", position.getCourse() <= 360); + Assert.assertNotNull("protocol is null", position.getProtocol()); + } } diff --git a/test/org/traccar/helper/ChannelBufferToolsTest.java b/test/org/traccar/helper/ChannelBufferToolsTest.java index 6e2c6310c..6733a8f2a 100644 --- a/test/org/traccar/helper/ChannelBufferToolsTest.java +++ b/test/org/traccar/helper/ChannelBufferToolsTest.java @@ -1,8 +1,7 @@ package org.traccar.helper; import org.jboss.netty.buffer.ChannelBuffers; - -import static org.junit.Assert.*; +import org.junit.Assert; import org.junit.Test; public class ChannelBufferToolsTest { @@ -12,7 +11,15 @@ public class ChannelBufferToolsTest { byte[] buf = {0x01, (byte) 0x90, 0x34}; int result = ChannelBufferTools.readHexInteger( ChannelBuffers.wrappedBuffer(buf), 5); - assertEquals(1903, result); + Assert.assertEquals(1903, result); + } + + @Test + public void testReadCoordinate() { + byte[] buf = {0x03, (byte) 0x85, 0x22, 0x59, 0x34}; + double result = ChannelBufferTools.readCoordinate( + ChannelBuffers.wrappedBuffer(buf)); + Assert.assertEquals(38.870989, result, 0.00001); } } diff --git a/test/org/traccar/helper/ObdDecoderTest.java b/test/org/traccar/helper/ObdDecoderTest.java new file mode 100644 index 000000000..238f3e0a6 --- /dev/null +++ b/test/org/traccar/helper/ObdDecoderTest.java @@ -0,0 +1,19 @@ +package org.traccar.helper; + +import org.junit.Assert; +import org.junit.Test; + +public class ObdDecoderTest { + + @Test + public void testDecode() { + + Assert.assertEquals(83, ObdDecoder.decode(0x01, 0x05, "7b").getValue()); + Assert.assertEquals(1225, ObdDecoder.decode(0x01, 0x0C, "1324").getValue()); + Assert.assertEquals(20, ObdDecoder.decode(0x01, 0x0D, "14").getValue()); + Assert.assertEquals(64050, ObdDecoder.decode(0x01, 0x31, "fa32").getValue()); + Assert.assertEquals(25, ObdDecoder.decode(0x01, 0x2F, "41").getValue()); + + } + +} diff --git a/test/org/traccar/helper/PatternBuilderTest.java b/test/org/traccar/helper/PatternBuilderTest.java index 36054bcea..975cc1621 100644 --- a/test/org/traccar/helper/PatternBuilderTest.java +++ b/test/org/traccar/helper/PatternBuilderTest.java @@ -8,7 +8,7 @@ public class PatternBuilderTest { @Test public void testPatternBuilder() { Assert.assertEquals("\\$GPRMC", new PatternBuilder().text("$GPRMC").toString()); - Assert.assertEquals("(\\d{2}\\.\\p{XDigit}+)", new PatternBuilder().number("(dd.x+)").toString()); + Assert.assertEquals("(\\d{2}\\.[0-9a-fA-F]+)", new PatternBuilder().number("(dd.x+)").toString()); Assert.assertEquals("a(?:bc)?", new PatternBuilder().text("a").text("b").text("c").optional(2).toString()); Assert.assertEquals("a|b", new PatternBuilder().expression("a|b").toString()); Assert.assertEquals("ab\\|", new PatternBuilder().expression("ab|").toString()); diff --git a/test/org/traccar/protocol/Ardi01ProtocolDecoderTest.java b/test/org/traccar/protocol/Ardi01ProtocolDecoderTest.java index be5578683..717dfd958 100644 --- a/test/org/traccar/protocol/Ardi01ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Ardi01ProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class Ardi01ProtocolDecoderTest extends ProtocolDecoderTest { Ardi01ProtocolDecoder decoder = new Ardi01ProtocolDecoder(new Ardi01Protocol()); verifyPosition(decoder, text( + "013227003054776,20141010052719,24.4736042,56.8445807,110,289,40,7,5,78,-1"), + position("2014-10-10 05:27:19.000", true, 56.84458, 24.47360)); + + verifyPosition(decoder, text( "013227003054776,20141010052719,24.4736042,56.8445807,110,289,40,7,5,78,-1")); } diff --git a/test/org/traccar/protocol/AtrackProtocolDecoderTest.java b/test/org/traccar/protocol/AtrackProtocolDecoderTest.java index 882501e9e..72c54f1e6 100644 --- a/test/org/traccar/protocol/AtrackProtocolDecoderTest.java +++ b/test/org/traccar/protocol/AtrackProtocolDecoderTest.java @@ -1,9 +1,7 @@ package org.traccar.protocol; -import org.jboss.netty.buffer.ChannelBuffers; import org.junit.Test; import org.traccar.ProtocolDecoderTest; -import org.traccar.helper.ChannelBufferTools; public class AtrackProtocolDecoderTest extends ProtocolDecoderTest { @@ -12,12 +10,26 @@ public class AtrackProtocolDecoderTest extends ProtocolDecoderTest { AtrackProtocolDecoder decoder = new AtrackProtocolDecoder(new AtrackProtocol()); + decoder.setLongDate(true); + + verifyPositions(decoder, binary( + "0203b494003c00eb00014104d8dd3a3e07de011b0b1f0307de011b0b1f0307de011b0b1f0300307f28030574d30000020000000600160100020000000007d007d000")); + + decoder.setLongDate(false); + + decoder.setCustom(true); + + verifyPositions(decoder, binary( + "405025e30096eb730001452efaf6a7d6562fe4f8562fe4f7562fe52c02a006d902273f810064650000e0f5000a0100000000000007d007d000254349255341254d5625425625475125415400090083002a1a000001a8562fe4f8562fe4f7562fe52c02a006d902273f810064020000e0f5000a0100000000000007d007d000254349255341254d5625425625475125415400090083002a1a000001a8")); + + decoder.setCustom(false); + verifyNothing(decoder, binary( "fe0200014104d8f196820001")); - // invalid GPS data - //verifyPositions(decoder, binary( - // "40503835003300070001441c3d8ed1c400000000000000c9000000c900000000000000000000020000000003de0100000000000007d007d000")); + verifyPositions(decoder, binary( + "40503835003300070001441c3d8ed1c400000000000000c9000000c900000000000000000000020000000003de0100000000000007d007d000"), + position("1970-01-01 00:00:00.000", true, 0.00000, 0.00000)); verifyPositions(decoder, binary( "4050993f005c000200014104d8f19682525666c252568c3c52568c63ffc8338402698885000002000009cf03de0100000000000007d007d000525666c252568c5a52568c63ffc8338402698885000002000009cf03de0100000000000007d007d000")); @@ -28,13 +40,6 @@ public class AtrackProtocolDecoderTest extends ProtocolDecoderTest { verifyPositions(decoder, binary( "40501e58003301e000014104d8f19682525ecd5d525ee344525ee35effc88815026ab4d70000020000104403de01000b0000000007d007d000000000000000")); - // 7-byte date - //verifyPosition(decoder, binary( - // "0203b494003c00eb00014104d8dd3a3e07de011b0b1f0307de011b0b1f0307de011b0b1f0300307f28030574d30000020000000600160100020000000007d007d000")); - - //verifyPosition(decoder, binary( - // "4050d2c500da055200014104d8f19682530755515307555053075581ffbba66a0231295c001902000000da000a0100830000000007d007d000000000001200080e090085530755605307555f53075582ffbbb04102313b4b001802000000e0000c0100850000000007d007d000000000001200080d0000865307556f5307556e53075582ffbbbbea02314b49002402000000e5000a01007b0000000007d007d000000000001200080d0200855307557e5307557d53075582ffbbc98702315982002502000000ea000901007a0000000007d007d000000000001300180d08007b")); - } } diff --git a/test/org/traccar/protocol/AutoFon45ProtocolDecoderTest.java b/test/org/traccar/protocol/AutoFon45ProtocolDecoderTest.java index 50df04117..f739c6709 100644 --- a/test/org/traccar/protocol/AutoFon45ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/AutoFon45ProtocolDecoderTest.java @@ -12,9 +12,16 @@ public class AutoFon45ProtocolDecoderTest extends ProtocolDecoderTest { AutoFon45ProtocolDecoder decoder = new AutoFon45ProtocolDecoder(new AutoFon45Protocol()); verifyNothing(decoder, binary( + "41035151305289931441139602662095148807")); + + verifyNothing(decoder, binary( "41032125656985547543619173484002123481")); verifyPosition(decoder, binary( + "023E00001E004D411EFA01772F185285009C48041F1E366C2961380F26B10B00911C"), + position("2010-01-27 04:00:08.000", true, 54.73838, 56.10343)); + + verifyPosition(decoder, binary( "023E00001E004D411EFA01772F185285009C48041F1E366C2961380F26B10B00911C")); } } diff --git a/test/org/traccar/protocol/CarTrackProtocolDecoderTest.java b/test/org/traccar/protocol/CarTrackProtocolDecoderTest.java index 6b26607d7..a23dea444 100644 --- a/test/org/traccar/protocol/CarTrackProtocolDecoderTest.java +++ b/test/org/traccar/protocol/CarTrackProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class CarTrackProtocolDecoderTest extends ProtocolDecoderTest { CarTrackProtocolDecoder decoder = new CarTrackProtocolDecoder(new CarTrackProtocol()); verifyPosition(decoder, text( + "$$2222234???????&A9955&B102904.000,A,2233.0655,N,11404.9440,E,0.00,,030109,,*17|6.3|&C0100000100&D000024?>&E10000000"), + position("2009-01-03 10:29:04.000", true, 22.55109, 114.08240)); + + verifyPosition(decoder, text( "$$2222234???????&A9955&B102904.000,A,2233.0655,N,11404.9440,E,0.00,,030109,,*17|6.3|&C0100000100&D000024?>&E10000000&Y00100020")); verifyPosition(decoder, text( diff --git a/test/org/traccar/protocol/CastelProtocolDecoderTest.java b/test/org/traccar/protocol/CastelProtocolDecoderTest.java index be4cab227..49fa5b0be 100644 --- a/test/org/traccar/protocol/CastelProtocolDecoderTest.java +++ b/test/org/traccar/protocol/CastelProtocolDecoderTest.java @@ -13,6 +13,39 @@ public class CastelProtocolDecoderTest extends ProtocolDecoderTest { CastelProtocolDecoder decoder = new CastelProtocolDecoder(new CastelProtocol()); + //verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, + // "4040590004313030303030303030303800000000000000000040010072f53f56c25240560000000078b00900000000009c3100000000030100011900030001090b0f080106c04fe40b4037310c0060e001ff018d01e05e0d0a")); + + verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "404055000431303031313132353239393837000000000000001002C1F0695230086A529C911100000000000F890000A60500000000036301014CFF000001190A0D0539191480D60488C5721800000000BF8A640D0A")); + + verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "40406000043130303131313235323939383700000000000000400705000000C1F0695249F469529C9111000000000069830000D80040000400036401014C04030001190A0D04201E1480D60488C5721800000000AF0101060F000F00EA1E0D0A")); + + verifyNothing(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "404057000431303031313132353239393837000000000000004002C1F06952F0F169529C9111000000000069830000470000000400036401014C01030078000505210C210D210F21102101073BE8030064280AEB930D0A")); + + verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "40405900043130303131313235323939383700000000000000400101C1F06952E7F069529C9111000000000069830000070000000400036401014C00030001190A0D0412041480D60488C57218000000009F01E803ED9A0D0A")); + + verifyNothing(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "4040B9000431303031313132353239393837000000000000004005C1F069521BF169529C9111000000000069830000130000000400036401014C0003000022032104210521062107210C210D210E210F2110211121132115211C211F21212124212E212F2130213121322133213C214221432144214521472149214A214C214D214E210100643B6232E803003E64280A3C24FE00010E010F00D5805A483C640000000000010000E02E000000066400000500000000A7710D0A")); + + verifyNothing(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "404043000431303031313132353239393837000000000000004006C1F0695209F169529C91110000000000698300000D0000000400036401014C00030000009AF40D0A")); + + verifyNothing(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "404086000431303031313132353239393837000000000000004004C1F0695200F169529C91110000000000698300000D0000000400036401014C00030022032104210521062107210C210D210E210F2110211121132115211C211F21212124212E212F2130213121322133213C214221432144214521472149214A214C214D214E219AE90D0A")); + + verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "40407F000431303031313132353239393837000000000000001001C1F06952FDF069529C91110000000000698300000C0000000000036401014C00030001190A0D04121A1480D60488C5721800000000AF4944445F3231364730325F532056312E322E31004944445F3231364730325F482056312E322E31000000DF640D0A")); + + verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "404044000c3631313135303030303935360000000000000000420600011e0a0f0b1312864fcd08c07a13030100640acf000004000a000000000000007ba083a66ad80d0a")); + + verifyPosition(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "40405c000c363131313530303030393536000000000000000040011c0a0f0e362dca53cd0860831303000000000300000000ff000000000000007ba083a650542d3639305f56312e312e320050542d3639302056312e32008a020d0a")); + verifyNothing(decoder, binary(ByteOrder.LITTLE_ENDIAN, "4040450004323132474c31313433303035303033000000000040082ca89b55a6a99b555c57000000000000c40200000b0000001400036401111f000302f5533bd653f10d0a")); diff --git a/test/org/traccar/protocol/CityeasyProtocolDecoderTest.java b/test/org/traccar/protocol/CityeasyProtocolDecoderTest.java index 33ee51c4f..7f39e5dd6 100644 --- a/test/org/traccar/protocol/CityeasyProtocolDecoderTest.java +++ b/test/org/traccar/protocol/CityeasyProtocolDecoderTest.java @@ -13,6 +13,15 @@ public class CityeasyProtocolDecoderTest extends ProtocolDecoderTest { CityeasyProtocolDecoder decoder = new CityeasyProtocolDecoder(new CityeasyProtocol()); + verifyAttributes(decoder, binary( + "545400853575570249020100033b3430342c34352c31303638312c31313632312c33352c31303638312c31313632322c32332c31303638312c32383938332c32332c31303638312c31313632332c32312c31303638312c32333338312c31372c31303638312c32323538332c31372c31303638312c32363434312c31330000000d352e0d0a")); + + verifyNothing(decoder, binary( + "54540019357557024902010002520704100000000bbe700d0a")); + + verifyNothing(decoder, binary( + "5454001735755702490201434a01000000000c24280d0a")); + verifyNothing(decoder, binary( "545400153520000000000100010000000111000D0A")); @@ -20,7 +29,8 @@ public class CityeasyProtocolDecoderTest extends ProtocolDecoderTest { "54540019357557024902000002520704300000000376390d0a")); verifyPosition(decoder, binary( - "5454006135200000000001000332303134313131303039353430392C412C342C4E2C32322E3533373232382C452C3131342E3032323737342C302E312C312E392C35302E363B3436302C302C31303137332C343635322C34310000000B63130D0A")); + "5454006135200000000001000332303134313131303039353430392C412C342C4E2C32322E3533373232382C452C3131342E3032323737342C302E312C312E392C35302E363B3436302C302C31303137332C343635322C34310000000B63130D0A"), + position("2014-11-10 09:54:09.000", true, 22.53723, 114.02277)); verifyPosition(decoder, binary( "5454006135200000000001000432303134313131303039353330362C412C352C4E2C32322E3533373233352C452C3131342E3032323838312C302E322C312E362C35342E313B3436302C302C31303137332C343635322C343100000045EC620D0A")); diff --git a/test/org/traccar/protocol/EasyTrackProtocolDecoderTest.java b/test/org/traccar/protocol/EasyTrackProtocolDecoderTest.java index 9e1dfce34..f926bdee3 100644 --- a/test/org/traccar/protocol/EasyTrackProtocolDecoderTest.java +++ b/test/org/traccar/protocol/EasyTrackProtocolDecoderTest.java @@ -14,7 +14,8 @@ public class EasyTrackProtocolDecoderTest extends ProtocolDecoderTest { "*ET,135790246811221,GZ,0001,0005")); verifyPosition(decoder, text( - "*ET,135790246811221,DW,A,0A090D,101C0D,00CF27C6,0413FA4E,0000,0000,00000000,20,4,0000,00F123")); + "*ET,135790246811221,DW,A,0A090D,101C0D,00CF27C6,0413FA4E,0000,0000,00000000,20,4,0000,00F123"), + position("2010-09-13 16:28:13.000", true, 22.62689, 114.03021)); verifyPosition(decoder, text( "*ET,135790246811221,DW,A,050915,0C2A27,00CE5954,04132263,0000,0000,01000000,20,4,0000,001254")); @@ -27,7 +28,7 @@ public class EasyTrackProtocolDecoderTest extends ProtocolDecoderTest { verifyPosition(decoder, text( "*ET,358155100003016,HB,A,0d081e,07381e,8038ee09,03d2e9be,004f,0000,40c00000,0f,100,0000,00037c,29")); - + verifyPosition(decoder, text( "*ET,358155100003016,HB,A,0d081e,073900,8038ee2f,03d2e9fd,0114,0000,40c00000,12,100,0000,00037c,32")); diff --git a/test/org/traccar/protocol/EnforaProtocolDecoderTest.java b/test/org/traccar/protocol/EnforaProtocolDecoderTest.java index da1427611..0333d57e9 100644 --- a/test/org/traccar/protocol/EnforaProtocolDecoderTest.java +++ b/test/org/traccar/protocol/EnforaProtocolDecoderTest.java @@ -17,7 +17,8 @@ public class EnforaProtocolDecoderTest extends ProtocolDecoderTest { "003B000502000000000820202020202030313130373030303035373032363720383A000000000D00508401358E640032B37700000367B00000A804")); verifyPosition(decoder, binary( - "007100040200202020202020202020382020202020202031323334353637383930313233343520313320244750524D432C3232333135322E30302C412C333530392E3836303539342C4E2C30333332322E3734333838372C452C302E302C302E302C3032303631322C2C2C412A35320D0A")); + "007100040200202020202020202020382020202020202031323334353637383930313233343520313320244750524D432C3232333135322E30302C412C333530392E3836303539342C4E2C30333332322E3734333838372C452C302E302C302E302C3032303631322C2C2C412A35320D0A"), + position("2012-06-02 22:31:52.000", true, 35.16434, 33.37906)); verifyPosition(decoder, binary( "007600040200202020202020202020382020202020202030313138393230303036303831383920313320244750524D432C3137313834312E30302C412C333530392E3835323431302C4E2C30333332322E3735393131332C452C302E302C302E302C3137303731322C332E342C572C412A32350D0A00")); diff --git a/test/org/traccar/protocol/Ev603ProtocolDecoderTest.java b/test/org/traccar/protocol/Ev603ProtocolDecoderTest.java deleted file mode 100644 index a843fcf21..000000000 --- a/test/org/traccar/protocol/Ev603ProtocolDecoderTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.traccar.protocol; - -import org.junit.Test; -import org.traccar.ProtocolDecoderTest; - -public class Ev603ProtocolDecoderTest extends ProtocolDecoderTest { - - @Test - public void testDecode() throws Exception { - - Ev603ProtocolDecoder decoder = new Ev603ProtocolDecoder(new Ev603Protocol()); - - verifyNothing(decoder, text( - "!1,123456789012345")); - - verifyNothing(decoder, text( - "!5,17,V")); - - verifyNothing(decoder, text( - "!1,860719027585011")); - - verifyPosition(decoder, text( - "!A,26/10/12,00:28:41,7.770385,-72.215706,0.0,25101,0")); - - verifyPosition(decoder, text( - "!A,01/12/10,13:25:35,22.641724,114.023666,000.1,281.6,0")); - - verifyPosition(decoder, text( - "!D,08/07/15,04:01:32,40.428257,-3.704808,0,0,170001,701.7,22,5,14,0")); - - verifyPosition(decoder, text( - "!D,08/07/15,04:55:13,40.428257,-3.704932,0,0,180001,680.0,8,8,13,0")); - - verifyPosition(decoder, text( - "!D,08/07/15,02:01:32,40.428230,-3.704950,4,170,170001,682.7,43,6,13,0")); - - } - -} diff --git a/test/org/traccar/protocol/FlextrackProtocolDecoderTest.java b/test/org/traccar/protocol/FlextrackProtocolDecoderTest.java index 049b0e95e..d7c773b01 100644 --- a/test/org/traccar/protocol/FlextrackProtocolDecoderTest.java +++ b/test/org/traccar/protocol/FlextrackProtocolDecoderTest.java @@ -21,6 +21,10 @@ public class FlextrackProtocolDecoderTest extends ProtocolDecoderTest { "-2,UNITSTAT,20060101,123442,1080424008,N0.00.0000,E0.00.0000,0,0,0,4129,-61,2,23866,0,999,A214,63,2EE2,3471676")); verifyPosition(decoder, text( + "-2,UNITSTAT,20050205,181923,7000004634,N55.46.0812,E009.21.1665,122,198,6,3934,-81,01A8,23802,213,55,37FD,45,0055,12878"), + position("2005-02-05 18:19:23.000", true, 55.76802, 9.35278)); + + verifyPosition(decoder, text( "-2,UNITSTAT,20050205,181923,7000004634,N55.46.0812,E009.21.1665,122,198,6,3934,-81,01A8,23802,213,55,37FD,45,0055,12878")); } diff --git a/test/org/traccar/protocol/Gl100ProtocolDecoderTest.java b/test/org/traccar/protocol/Gl100ProtocolDecoderTest.java index 52c331f13..f9fccd187 100644 --- a/test/org/traccar/protocol/Gl100ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Gl100ProtocolDecoderTest.java @@ -15,7 +15,8 @@ public class Gl100ProtocolDecoderTest extends ProtocolDecoderTest { "AT+GTHBD=HeartBeat,359231030000010,20090101000000,11F0,0102120204")); verifyPosition(decoder, text( - "+RESP:GTSOS,359231030000010,0,0,0,1,4.3,92,70.0,1,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,11F0,0102120204")); + "+RESP:GTSOS,359231030000010,0,0,0,1,4.3,92,70.0,1,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,11F0,0102120204"), + position("2009-01-01 00:00:00.000", false, 31.22207, 121.35434)); verifyPosition(decoder, text( "+RESP:GTRTL,359231030000010,0,0,0,1,4.3,92,70.0,1,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,11F0,0102120204")); diff --git a/test/org/traccar/protocol/Gl200ProtocolDecoderTest.java b/test/org/traccar/protocol/Gl200ProtocolDecoderTest.java index 4596a5c90..1f5242b9c 100644 --- a/test/org/traccar/protocol/Gl200ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Gl200ProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class Gl200ProtocolDecoderTest extends ProtocolDecoderTest { Gl200ProtocolDecoder decoder = new Gl200ProtocolDecoder(new Gl200Protocol()); + verifyPosition(decoder, text( + "+RESP:GTIDA,06020A,862170013895931,,,D2C4FBC5,1,1,1,0.8,0,22.2,117.198630,31.845229,20120802121626,0460,0000,5663,2BB9,00,0.0,,,,,20120802121627,008E$")); + verifyAttributes(decoder, text( "+RESP:GTINF,1F0101,135790246811220,1G1JC5444R7252367,,16,898600810906F8048812,16,0,1,12000,,4.2,0,0,,,20090214013254,,,,,,+0800,0,20090214093254,11F0$")); diff --git a/test/org/traccar/protocol/GotopProtocolDecoderTest.java b/test/org/traccar/protocol/GotopProtocolDecoderTest.java index dcafd5add..abc967076 100644 --- a/test/org/traccar/protocol/GotopProtocolDecoderTest.java +++ b/test/org/traccar/protocol/GotopProtocolDecoderTest.java @@ -10,16 +10,19 @@ public class GotopProtocolDecoderTest extends ProtocolDecoderTest { GotopProtocolDecoder decoder = new GotopProtocolDecoder(new GotopProtocol()); - verifyNothing(decoder, text( "")); + verifyNothing(decoder, text( + "")); - verifyNothing(decoder, text( "353327020412763,CMD-X")); + verifyNothing(decoder, text( + "353327020412763,CMD-X")); verifyPosition(decoder, text( "013226009991924,CMD-T,A,DATE:130802,TIME:153721,LAT:25.9757433S,LOT:028.1087816E,Speed:000.0,X-X-X-X-81-26,000,65501-00A0-4B8E")); verifyPosition(decoder, text( - "353327020115804,CMD-T,A,DATE:090329,TIME:223252,LAT:22.7634066N,LOT:114.3964783E,Speed:000.0,84-20,000")); - + "353327020115804,CMD-T,A,DATE:090329,TIME:223252,LAT:22.7634066N,LOT:114.3964783E,Speed:000.0,84-20,000"), + position("2009-03-29 22:32:52.000", true, 22.76341, 114.39648)); + verifyPosition(decoder, text( "353327020115804,CMD-T,A,DATE:090329,TIME:223252,LAT:22.7634066N,LOT:114.3964783E,Speed:000.0,1-1-0-84-20,000")); diff --git a/test/org/traccar/protocol/Gps103ProtocolDecoderTest.java b/test/org/traccar/protocol/Gps103ProtocolDecoderTest.java index 09452c5e6..80d1424fc 100644 --- a/test/org/traccar/protocol/Gps103ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Gps103ProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class Gps103ProtocolDecoderTest extends ProtocolDecoderTest { Gps103ProtocolDecoder decoder = new Gps103ProtocolDecoder(new Gps103Protocol()); verifyPosition(decoder, text( + "imei:359710045559474,tracker,151030080103,,F,000101.000,A,5443.3834,N,02512.9071,E,0.00,0;"), + position("2015-10-30 00:01:01.000", true, 54.72306, 25.21512)); + + verifyPosition(decoder, text( "imei:359710049092324,tracker,151027025958,,F,235957.000,A,2429.5156,N,04424.5828,E,0.01,27.91,,0,0,,,;"), position("2015-10-26 23:59:57.000", true, 24.49193, 44.40971)); diff --git a/test/org/traccar/protocol/GpsGateProtocolDecoderTest.java b/test/org/traccar/protocol/GpsGateProtocolDecoderTest.java index 8652b24a6..2d21f53c9 100644 --- a/test/org/traccar/protocol/GpsGateProtocolDecoderTest.java +++ b/test/org/traccar/protocol/GpsGateProtocolDecoderTest.java @@ -10,20 +10,28 @@ public class GpsGateProtocolDecoderTest extends ProtocolDecoderTest { GpsGateProtocolDecoder decoder = new GpsGateProtocolDecoder(new GpsGateProtocol()); - verifyNothing(decoder, text( "$FRLIN,,user1,8IVHF*7A")); + verifyNothing(decoder, text( + "$FRLIN,,user1,8IVHF*7A")); - verifyNothing(decoder, text( "$FRLIN,,354503026292842,VGZTHKT*0C")); + verifyNothing(decoder, text( + "$FRLIN,,354503026292842,VGZTHKT*0C")); - verifyNothing(decoder, text( "$FRLIN,IMEI,1234123412341234,*7B")); + verifyNothing(decoder, text( + "$FRLIN,IMEI,1234123412341234,*7B")); - verifyNothing(decoder, text( "$FRLIN,,saab93_device,KLRFBGIVDJ*28")); + verifyNothing(decoder, text( + "$FRLIN,,saab93_device,KLRFBGIVDJ*28")); verifyPosition(decoder, text( - "$GPRMC,154403.000,A,6311.64120,N,01438.02740,E,0.000,0.0,270707,,*0A")); - + "$GPRMC,154403.000,A,6311.64120,N,01438.02740,E,0.000,0.0,270707,,*0A"), + position("2007-07-27 15:44:03.000", true, 63.19402, 14.63379)); + verifyPosition(decoder, text( "$GPRMC,074524,A,5553.73701,N,03728.90491,E,10.39,226.5,160614,0.0,E*75")); + verifyPosition(decoder, text( + "$GPRMC,154403.000,A,6311.64120,N,01438.02740,E,0.000,0.0,270707,,*0A")); + } } diff --git a/test/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java b/test/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java index 28237b5b2..fc3116577 100644 --- a/test/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java +++ b/test/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java @@ -16,7 +16,8 @@ public class GpsMarkerProtocolDecoderTest extends ProtocolDecoderTest { "$GM300350123456789012T100511123300G25000001772F185200000000000000005230298#")); verifyPosition(decoder, text( - "$GM200350123456789012T100511123300N55516789E03756123400000035230298#")); + "$GM200350123456789012T100511123300N55516789E03756123400000035230298#"), + position("2011-05-10 12:33:00.000", true, 55.86132, 37.93539)); verifyPosition(decoder, text( "$GM1350123456789012T1005111233N55516789E03756123400000035200298#")); diff --git a/test/org/traccar/protocol/GpsmtaProtocolDecoderTest.java b/test/org/traccar/protocol/GpsmtaProtocolDecoderTest.java index cd1257de7..8d7b6ab0f 100644 --- a/test/org/traccar/protocol/GpsmtaProtocolDecoderTest.java +++ b/test/org/traccar/protocol/GpsmtaProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class GpsmtaProtocolDecoderTest extends ProtocolDecoderTest { GpsmtaProtocolDecoder decoder = new GpsmtaProtocolDecoder(new GpsmtaProtocol()); verifyPosition(decoder, text( + "3085a94ef459 1446536867 49.81621 24.054207 1 0 22 0 10 12 24 0 0")); + + verifyPosition(decoder, text( "864528021249771 1446116686 49.85073 24.004438 0 217 6 338 00 59 27 0 0")); verifyPosition(decoder, text( diff --git a/test/org/traccar/protocol/Gt02ProtocolDecoderTest.java b/test/org/traccar/protocol/Gt02ProtocolDecoderTest.java index 76590fe3f..4f086d4f3 100644 --- a/test/org/traccar/protocol/Gt02ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Gt02ProtocolDecoderTest.java @@ -1,9 +1,7 @@ package org.traccar.protocol; -import org.jboss.netty.buffer.ChannelBuffers; import org.junit.Test; import org.traccar.ProtocolDecoderTest; -import org.traccar.helper.ChannelBufferTools; public class Gt02ProtocolDecoderTest extends ProtocolDecoderTest { @@ -13,7 +11,8 @@ public class Gt02ProtocolDecoderTest extends ProtocolDecoderTest { Gt02ProtocolDecoder decoder = new Gt02ProtocolDecoder(new Gt02Protocol()); verifyPosition(decoder, binary( - "68682500000123456789012345000110010101010101026B3F3E026B3F3E000000000000000000010D0A")); + "68682500000123456789012345000110010101010101026B3F3E026B3F3E000000000000000000010D0A"), + position("2001-01-01 01:01:01.000", true, -22.54610, -22.54610)); verifyNothing(decoder, binary( "6868110603035889905101276600001a0402292d0d0a")); diff --git a/test/org/traccar/protocol/HaicomProtocolDecoderTest.java b/test/org/traccar/protocol/HaicomProtocolDecoderTest.java index df1c33a06..f8a35499a 100644 --- a/test/org/traccar/protocol/HaicomProtocolDecoderTest.java +++ b/test/org/traccar/protocol/HaicomProtocolDecoderTest.java @@ -11,7 +11,8 @@ public class HaicomProtocolDecoderTest extends ProtocolDecoderTest { HaicomProtocolDecoder decoder = new HaicomProtocolDecoder(new HaicomProtocol()); verifyPosition(decoder, text( - "$GPRS012497007097169,T100001,150618,230031,5402267400332464,0004,2014,000001,,,1,00#V040*")); + "$GPRS012497007097169,T100001,150618,230031,5402267400332464,0004,2014,000001,,,1,00#V040*"), + position("2015-06-18 23:00:31.000", true, 40.37790, -3.54107)); verifyPosition(decoder, text( "$GPRS123456789012345,602S19A,100915,063515,7240649312041079,0019,3156,111000,10004,0000,11111,00LH#V037")); diff --git a/test/org/traccar/protocol/HuabaoFrameDecoderTest.java b/test/org/traccar/protocol/HuabaoFrameDecoderTest.java new file mode 100644 index 000000000..923096f50 --- /dev/null +++ b/test/org/traccar/protocol/HuabaoFrameDecoderTest.java @@ -0,0 +1,20 @@ +package org.traccar.protocol; + +import org.junit.Assert; +import org.junit.Test; +import org.traccar.ProtocolDecoderTest; + +public class HuabaoFrameDecoderTest extends ProtocolDecoderTest { + + @Test + public void testDecode() throws Exception { + + HuabaoFrameDecoder decoder = new HuabaoFrameDecoder(); + + Assert.assertEquals( + binary("7e307e087d557e"), + decoder.decode(null, null, binary("7e307d02087d01557e"))); + + } + +} diff --git a/test/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/test/org/traccar/protocol/HuabaoProtocolDecoderTest.java new file mode 100644 index 000000000..0968d6d9c --- /dev/null +++ b/test/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolDecoderTest; + +public class HuabaoProtocolDecoderTest extends ProtocolDecoderTest { + + @Test + public void testDecode() throws Exception { + + HuabaoProtocolDecoder decoder = new HuabaoProtocolDecoder(new HuabaoProtocol()); + + verifyNothing(decoder, binary( + "7e0100002d007089994489002800000000000000000048422d523033474244000000000000000000000031393036373531024142433030303030d17e")); + + } + +} diff --git a/test/org/traccar/protocol/IntellitracProtocolDecoderTest.java b/test/org/traccar/protocol/IntellitracProtocolDecoderTest.java index 9cba712bb..23d7fb48a 100644 --- a/test/org/traccar/protocol/IntellitracProtocolDecoderTest.java +++ b/test/org/traccar/protocol/IntellitracProtocolDecoderTest.java @@ -10,10 +10,12 @@ public class IntellitracProtocolDecoderTest extends ProtocolDecoderTest { IntellitracProtocolDecoder decoder = new IntellitracProtocolDecoder(new IntellitracProtocol()); - verifyNothing(decoder, text( "$OK:TRACKING")); + verifyNothing(decoder, text( + "$OK:TRACKING")); verifyPosition(decoder, text( - "101000001,20100304075545,121.64547,25.06200,0,0,61,7,2,1,0,0.046,0.000,20100304075546,0")); + "101000001,20100304075545,121.64547,25.06200,0,0,61,7,2,1,0,0.046,0.000,20100304075546,0"), + position("2010-03-04 07:55:45.000", true, 25.06200, 121.64547)); verifyPosition(decoder, text( "1010000002,20030217132813,121.646060,25.061725,20,157,133,7,0,11,15,0.096,0.000")); diff --git a/test/org/traccar/protocol/Jt600ProtocolDecoderTest.java b/test/org/traccar/protocol/Jt600ProtocolDecoderTest.java index 8acdbe15b..bcd87f9fb 100644 --- a/test/org/traccar/protocol/Jt600ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Jt600ProtocolDecoderTest.java @@ -15,7 +15,8 @@ public class Jt600ProtocolDecoderTest extends ProtocolDecoderTest { Jt600ProtocolDecoder decoder = new Jt600ProtocolDecoder(new Jt600Protocol()); verifyPosition(decoder, binary( - "24311021600111001B16021105591022329862114046227B0598095080012327951435161F")); + "24311021600111001B16021105591022329862114046227B0598095080012327951435161F"), + position("2011-02-16 05:59:10.000", true, 22.54977, -114.07705)); verifyPosition(decoder, binary( "24312082002911001B171012052831243810120255336425001907190003FD2B91044D1FA0")); @@ -27,7 +28,8 @@ public class Jt600ProtocolDecoderTest extends ProtocolDecoderTest { "24608111888821001B09060908045322564025113242329F0598000001003F0000002D00AB")); verifyPosition(decoder, buffer( - "(3110312099,W01,11404.6204,E,2232.9961,N,A,040511,063736,4,7,100,4,17,1,1,company)")); + "(3110312099,W01,11404.6204,E,2232.9961,N,A,040511,063736,4,7,100,4,17,1,1,company)"), + position("2011-05-04 06:37:36.000", true, 22.54994, 114.07701)); verifyPosition(decoder, buffer( "(3120820029,W01,02553.3555,E,2438.0997,S,A,171012,053339,0,8,20,6,31,5,20,20)")); diff --git a/test/org/traccar/protocol/MegastekProtocolDecoderTest.java b/test/org/traccar/protocol/MegastekProtocolDecoderTest.java index 4ccf2a7e0..9046b3928 100644 --- a/test/org/traccar/protocol/MegastekProtocolDecoderTest.java +++ b/test/org/traccar/protocol/MegastekProtocolDecoderTest.java @@ -11,7 +11,8 @@ public class MegastekProtocolDecoderTest extends ProtocolDecoderTest { MegastekProtocolDecoder decoder = new MegastekProtocolDecoder(new MegastekProtocol()); verifyPosition(decoder, text( - "$MGV002,860719020193193,DeviceName,R,240214,104742,A,2238.20471,N,11401.97967,E,00,03,00,1.20,0.462,356.23,137.9,1.5,460,07,262C,0F54,25,0000,0000,0,0,0,28.5,28.3,,,100,Timer;!")); + "$MGV002,860719020193193,DeviceName,R,240214,104742,A,2238.20471,N,11401.97967,E,00,03,00,1.20,0.462,356.23,137.9,1.5,460,07,262C,0F54,25,0000,0000,0,0,0,28.5,28.3,,,100,Timer;!"), + position("2014-02-24 10:47:42.000", true, 22.63675, 114.03299)); verifyPosition(decoder, text( "STX2010101801 j$GPRMC,101053.000,A,2232.7607,N,11404.7669,E,0.00,,231110,,,A*7F,460,00,2795,0E6A,14,94,1000,0000,91,Timer;1D")); diff --git a/test/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/test/org/traccar/protocol/MeitrackProtocolDecoderTest.java index 2c513272c..88d11d551 100644 --- a/test/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/test/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -12,8 +12,9 @@ public class MeitrackProtocolDecoderTest extends ProtocolDecoderTest { MeitrackProtocolDecoder decoder = new MeitrackProtocolDecoder(new MeitrackProtocol()); verifyPosition(decoder, buffer( - "$$A158,79007001520234,AAA,35,40.996370,-8.575065,150730184834,A,8,24,0,1,1.3,173,32573389,31405012,268|3|2BC0|250B,2000,|||0A2D|0000,00000001,,50,,,,,,,,,,,,,*4A")); - + "$$A158,79007001520234,AAA,35,40.996370,-8.575065,150730184834,A,8,24,0,1,1.3,173,32573389,31405012,268|3|2BC0|250B,2000,|||0A2D|0000,00000001,,50,,,,,,,,,,,,,*4A"), + position("2015-07-30 18:48:34.000", true, 40.99637, -8.57507)); + verifyPosition(decoder, buffer( "$$G145,862106024274815,AAA,35,-1.287125,36.906061,150530054639,A,10,13,12,67,0.8,1621,38359791,42330881,639|2|FB2|2F3,0000,3|0|0|A58|432,,,1,0009,*26")); @@ -63,7 +64,8 @@ public class MeitrackProtocolDecoderTest extends ProtocolDecoderTest { "$$J163,123123123123123,AFF,0004,35,58.588926,16.180473,140928192856,A,10,27,0,161,1.2,19,1648894,435695,240|24|88B9|E435,0000,|||0A22|0000,00000001,,50,,,,,,,,,,,,,*70\r\n")); verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, - "24245838362c3336393830303031343039303032312c4343432c020134000100000023381f91ffe354b806c5e3121b0009130000000000000000d33801007cbf0200fe0101000435feeb02000500a3010000000000002a62650d0a")); + "24245838362c3336393830303031343039303032312c4343432c020134000100000023381f91ffe354b806c5e3121b0009130000000000000000d33801007cbf0200fe0101000435feeb02000500a3010000000000002a62650d0a"), + position("2014-05-24 04:59:49.000", false, -7.26650, 112.74365)); verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, "2424473937302c3336393830303031333436303637342c4343432c020134005b000000010ce304035db9e000ec6f591a000013000000000c001801edb70200c96d0100e60001004838576501000300a101c20400000000010ce304035db9e000ee6f591a000013000000000c001801edb70200ca6d0100e60001004838576501000300a101c20400000000010ce304035db9e000ef6f591a000013000000000c001801edb70200cc6d0100e60001004838576501000300a101c20400000000020ce304035db9e000f76f591a000016000000000c001801edb70200d36d0100e60001004838576502000300a101bf04000000000a0ce304035db9e000f76f591a000016000000000c001801edb70200d46d0100e60001004838576500000300a101bf0400000000020ce304035db9e000fb6f591a000016000000000c001801edb70200d86d0100e60001004838576502000300a101760400000000180ce304035db9e000fc6f591a0000120000000000008c00edb70200d96d0100e60001004838576502000300a10176040000000019b1e2040323b9e0000b70591a0105150600bb0012002901edb70200e76d0100e60001004838576502000300a2017005000000002023e304031fb9e0001070591a010615070027010d001601fcb70200ec6d0100e60001004838576502000300a201800500000000201fe3040302b9e0001170591a010615090019010d001501feb70200ed6d0100e60001004838576502000300a2018005000000002018e30403dcb8e0001270591a0106150b0011010d00150100b80200ee6d0100e60001004838576502000300a2018005000000002036e3040345b8e0001570591a0107150b002d010b0013010ab80200f16d0100e60001004838576502000300a2018005000000002053e3040326b8e0001670591a0107150d0041010b0013010eb80200f26d0100e60001004838576502000300a2018005000000002070e3040310b8e0001770591a0107150e004f010b00130111b80200f36d0100e60001004838576502000300a2018005000000002095e3040306b8e0001870591a0107150d005a010b00140115b80200f46d0100e60001004838576502000300a20180050000000020b3e3040305b8e0001970591a0107150b0060010b00140118b80200f56d0100e60001004838576502000300a20183050000000020cfe3040308b8e0001a70591a0107150b0066010b0014011bb80200f66d0100e60001004838576502000300a20183050000000020eee304030cb8e0001b70591a0106170b0004000d0014011eb80200f76d0100e60001004838576502000300a2018305000000002a62350d0a")); diff --git a/test/org/traccar/protocol/MiniFinderProtocolDecoderTest.java b/test/org/traccar/protocol/MiniFinderProtocolDecoderTest.java index 5f6add6c5..04e5c1172 100644 --- a/test/org/traccar/protocol/MiniFinderProtocolDecoderTest.java +++ b/test/org/traccar/protocol/MiniFinderProtocolDecoderTest.java @@ -10,10 +10,36 @@ public class MiniFinderProtocolDecoderTest extends ProtocolDecoderTest { MiniFinderProtocolDecoder decoder = new MiniFinderProtocolDecoder(new MiniFinderProtocol()); - verifyNothing(decoder, text( "!1,860719020212696")); + verifyNothing(decoder, text( + "!1,123456789012345")); + + verifyNothing(decoder, text( + "!5,17,V")); + + verifyNothing(decoder, text( + "!1,860719027585011")); + + verifyPosition(decoder, text( + "!A,26/10/12,00:28:41,7.770385,-72.215706,0.0,25101,0")); + + verifyPosition(decoder, text( + "!A,01/12/10,13:25:35,22.641724,114.023666,000.1,281.6,0")); + + verifyPosition(decoder, text( + "!D,08/07/15,04:01:32,40.428257,-3.704808,0,0,170001,701.7,22,5,14,0")); + + verifyPosition(decoder, text( + "!D,08/07/15,04:55:13,40.428257,-3.704932,0,0,180001,680.0,8,8,13,0")); + + verifyPosition(decoder, text( + "!D,08/07/15,02:01:32,40.428230,-3.704950,4,170,170001,682.7,43,6,13,0")); + + verifyNothing(decoder, text( + "!1,860719020212696")); verifyPosition(decoder, text( - "!D,22/2/14,13:40:58,56.899601,14.811541,0,0,1,176.0,98,5,16,0")); + "!D,22/2/14,13:40:58,56.899601,14.811541,0,0,1,176.0,98,5,16,0"), + position("2014-02-22 13:40:58.000", true, 56.89960, 14.81154)); verifyPosition(decoder, text( "!D,22/2/14,13:47:51,56.899517,14.811665,0,0,b0001,179.3,97,5,16,0")); diff --git a/test/org/traccar/protocol/NavisProtocolDecoderTest.java b/test/org/traccar/protocol/NavisProtocolDecoderTest.java index c0d0357b0..51e3ec94a 100644 --- a/test/org/traccar/protocol/NavisProtocolDecoderTest.java +++ b/test/org/traccar/protocol/NavisProtocolDecoderTest.java @@ -19,6 +19,9 @@ public class NavisProtocolDecoderTest extends ProtocolDecoderTest { "404E5443010000007B000000130044342A3E533A383631373835303035323035303739")); verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "404e544301000000000000005a002e6c2a3e410125d7540100001512233a0b0a0f08026300000a000b000b00020000000000000000000c12233b0b0a0f03fd6d3f0fde603f00000000ba0051e0c845000000000000000000000000000000000000000000000080808080")); + + verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, "404E5443010000007B0000005A0050692A3E410125DB0E00000015110707110A0C0880630000AA39A2381600020000000000000000000C110708110A0CB389793F1AEF263F00000000120034F516440000000000000000000000FAFF000000FAFF000000FAFF80808080")); verifyNothing(decoder, binary(ByteOrder.LITTLE_ENDIAN, diff --git a/test/org/traccar/protocol/Pt3000ProtocolDecoderTest.java b/test/org/traccar/protocol/Pt3000ProtocolDecoderTest.java index cadc76928..7c01d6022 100644 --- a/test/org/traccar/protocol/Pt3000ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Pt3000ProtocolDecoderTest.java @@ -11,7 +11,8 @@ public class Pt3000ProtocolDecoderTest extends ProtocolDecoderTest { Pt3000ProtocolDecoder decoder = new Pt3000ProtocolDecoder(new Pt3000Protocol()); verifyPosition(decoder, text( - "%356939010012099,$GPRMC,124945.752,A,4436.6245,N,01054.4634,E,0.11,358.52,060408,,,A,+393334347445,N028d")); + "%356939010012099,$GPRMC,124945.752,A,4436.6245,N,01054.4634,E,0.11,358.52,060408,,,A,+393334347445,N028d"), + position("2008-04-06 12:49:45.000", true, 44.61041, 10.90772)); verifyPosition(decoder, text( "%356939010014433,$GPRMC,172821.000,A,4019.5147,N,00919.1160,E,0.00,,010613,,,A,+393998525043,N098d")); diff --git a/test/org/traccar/protocol/Pt502ProtocolDecoderTest.java b/test/org/traccar/protocol/Pt502ProtocolDecoderTest.java index b09082b2e..a811de3ce 100644 --- a/test/org/traccar/protocol/Pt502ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Pt502ProtocolDecoderTest.java @@ -11,7 +11,8 @@ public class Pt502ProtocolDecoderTest extends ProtocolDecoderTest { Pt502ProtocolDecoder decoder = new Pt502ProtocolDecoder(new Pt502Protocol()); verifyPosition(decoder, text( - "$POS,216769295715,163237.000,A,3258.1738,S,02755.4350,E,0.00,215.88,100915,,,A/0000,0//232300//5b3/")); + "$POS,216769295715,163237.000,A,3258.1738,S,02755.4350,E,0.00,215.88,100915,,,A/0000,0//232300//5b3/"), + position("2015-09-10 16:32:37.000", true, -32.96956, 27.92392)); verifyPosition(decoder, text( "$POS,11023456,033731.000,A,0335.2617,N,09841.1587,E,0.00,88.12,210615,,,A/0000,0/1f8/388900//f33//")); diff --git a/test/org/traccar/protocol/Stl060ProtocolDecoderTest.java b/test/org/traccar/protocol/Stl060ProtocolDecoderTest.java index f167f983a..3af99374d 100644 --- a/test/org/traccar/protocol/Stl060ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Stl060ProtocolDecoderTest.java @@ -11,8 +11,9 @@ public class Stl060ProtocolDecoderTest extends ProtocolDecoderTest { Stl060ProtocolDecoder decoder = new Stl060ProtocolDecoder(new Stl060Protocol()); verifyPosition(decoder, text( - "$1,357804048043099,D001,AP29AW0963,23/02/14,14:06:54,17248488N,078342226E,0.08,193.12,1,1,1,1,1,A")); - + "$1,357804048043099,D001,AP29AW0963,23/02/14,14:06:54,17248488N,078342226E,0.08,193.12,1,1,1,1,1,A"), + position("2014-02-23 14:06:54.000", true, 17.41415, 78.57038)); + verifyPosition(decoder, text( "$1,357804048043099,D001,AP29AW0963,12/05/14,07:39:57,1724.8564N,07834.2199E,0.00,302.84,1,1,1,1,1,A")); diff --git a/test/org/traccar/protocol/SuntechProtocolDecoderTest.java b/test/org/traccar/protocol/SuntechProtocolDecoderTest.java index 54cc77d6c..d0987f289 100644 --- a/test/org/traccar/protocol/SuntechProtocolDecoderTest.java +++ b/test/org/traccar/protocol/SuntechProtocolDecoderTest.java @@ -10,16 +10,19 @@ public class SuntechProtocolDecoderTest extends ProtocolDecoderTest { SuntechProtocolDecoder decoder = new SuntechProtocolDecoder(new SuntechProtocol()); - verifyNothing(decoder, text( "SA200ALV;317652")); + verifyNothing(decoder, text( + "SA200ALV;317652")); verifyPosition(decoder, text( - "ST910;Alert;123456;410;20141018;18:30:12;+37.478774;+126.889690;000.000;000.00;0;4.0;1;6002")); + "ST910;Alert;123456;410;20141018;18:30:12;+37.478774;+126.889690;000.000;000.00;0;4.0;1;6002"), + position("2014-10-18 18:30:12.000", true, 37.47877, 126.88969)); verifyPosition(decoder, text( "ST910;Alert;123456;410;20141018;18:30:12;+37.478774;+126.889690;000.000;000.00;0;4.0;1;6002;02;0;0310000100;450;01;-282;70;255;3;0")); verifyPosition(decoder, text( - "SA200STT;317652;042;20120718;15:37:12;16d41;-15.618755;-056.083241;000.024;000.00;8;1;41548;12.17;100000;2;1979")); + "SA200STT;317652;042;20120718;15:37:12;16d41;-15.618755;-056.083241;000.024;000.00;8;1;41548;12.17;100000;2;1979"), + position("2012-07-18 15:37:12.000", true, -15.61876, -56.08324)); verifyPosition(decoder, text( "SA200STT;317652;042;20120721;19:04:30;16d41;-15.618743;-056.083221;000.001;000.00;12;1;41557;12.21;000000;1;3125")); diff --git a/test/org/traccar/protocol/T55ProtocolDecoderTest.java b/test/org/traccar/protocol/T55ProtocolDecoderTest.java index ddabc8ee4..b7adee89b 100644 --- a/test/org/traccar/protocol/T55ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/T55ProtocolDecoderTest.java @@ -10,13 +10,17 @@ public class T55ProtocolDecoderTest extends ProtocolDecoderTest { T55ProtocolDecoder decoder = new T55ProtocolDecoder(new T55Protocol()); - verifyNothing(decoder, text( "$GPFID,ID123456ABC")); + verifyNothing(decoder, text( + "$GPFID,ID123456ABC")); - verifyNothing(decoder, text( "$PGID,359853000144328*0F")); + verifyNothing(decoder, text( + "$PGID,359853000144328*0F")); - verifyNothing(decoder, text( "$PCPTI,CradlePoint Test,184453,184453.0,6F*57")); + verifyNothing(decoder, text( + "$PCPTI,CradlePoint Test,184453,184453.0,6F*57")); - verifyNothing(decoder, text( "IMEI 351467108700000")); + verifyNothing(decoder, text( + "IMEI 351467108700000")); verifyPosition(decoder, text( "$GPRMC,012006,A,4828.10,N,1353.52,E,0.00,0.00,180915,020.3,E*42")); @@ -68,4 +72,19 @@ public class T55ProtocolDecoderTest extends ProtocolDecoderTest { } + @Test + public void testMaxonDecode() throws Exception { + + // Maxon devices can send NMEA before identification + + T55ProtocolDecoder decoder = new T55ProtocolDecoder(new T55Protocol()); + + verifyNothing(decoder, text( + "$GPRMC,012006,A,4828.10,N,1353.52,E,0.00,0.00,180915,020.3,E*42")); + + verifyPosition(decoder, text( + "$GPFID,ID123456ABC")); + + } + } diff --git a/test/org/traccar/protocol/T800xProtocolDecoderTest.java b/test/org/traccar/protocol/T800xProtocolDecoderTest.java new file mode 100644 index 000000000..56efa5a92 --- /dev/null +++ b/test/org/traccar/protocol/T800xProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolDecoderTest; + +public class T800xProtocolDecoderTest extends ProtocolDecoderTest { + + @Test + public void testDecode() throws Exception { + + T800xProtocolDecoder decoder = new T800xProtocolDecoder(new T800xProtocol()); + + verifyNothing(decoder, binary( + "232301001500020357367031063979150208625010")); + + verifyNothing(decoder, binary( + "232303000f00000357367031063979")); + + verifyPosition(decoder, binary( + "232304004200030357367031063979003c03842307d00000c80000050100008000008900890100000017b100151022121648b8ef0c4422969342cec5944100000110")); + + verifyPosition(decoder, binary( + "232302004200150357367031063979003c03842307d000004a0000050100004001009500940000000285ab001510281350477f710d4452819342d1ba944101160038")); + + verifyAttributes(decoder, binary( + "232302004200000357367031063979003c03842307d000008000000501000000010094009400000002a0b90015102814590694015a00620cf698620cf49e620cf498")); + + } + +} diff --git a/test/org/traccar/protocol/TaipProtocolDecoderTest.java b/test/org/traccar/protocol/TaipProtocolDecoderTest.java index d9f74f33d..d0e800ec1 100644 --- a/test/org/traccar/protocol/TaipProtocolDecoderTest.java +++ b/test/org/traccar/protocol/TaipProtocolDecoderTest.java @@ -11,7 +11,8 @@ public class TaipProtocolDecoderTest extends ProtocolDecoderTest { TaipProtocolDecoder decoder = new TaipProtocolDecoder(new TaipProtocol(), false); verifyPosition(decoder, text( - ">RGP230615010248-2682523-065236820000003007F4101;ID=0005;#0002;*2A<")); + ">RGP230615010248-2682523-065236820000003007F4101;ID=0005;#0002;*2A<"), + position("2015-06-23 01:02:48.000", true, -26.82523, -65.23682)); verifyPosition(decoder, text( ">RGP190805211932-3457215-058493640000000FFBF0300;ID=8251;#2122;*54<")); @@ -23,7 +24,8 @@ public class TaipProtocolDecoderTest extends ProtocolDecoderTest { "\r\n>REV691615354941+3570173+1397742703203212;ID=Test")); verifyPosition(decoder, text( - ">REV481599462982+2578391-0802945201228512;ID=Test")); + ">REV481599462982+2578391-0802945201228512;ID=Test"), + position("2010-09-02 17:29:42.000", true, 25.78391, -80.29452)); verifyPosition(decoder, text( ">REV131756153215+3359479-0075299001031332;VO=10568798;IO=310;SV=10;BL=4190;CV09=0;AD=0;AL=+47;ID=356612021059680")); diff --git a/test/org/traccar/protocol/TelikProtocolDecoderTest.java b/test/org/traccar/protocol/TelikProtocolDecoderTest.java index 4344fe070..49ea41165 100644 --- a/test/org/traccar/protocol/TelikProtocolDecoderTest.java +++ b/test/org/traccar/protocol/TelikProtocolDecoderTest.java @@ -14,8 +14,12 @@ public class TelikProtocolDecoderTest extends ProtocolDecoderTest { "0026436729|232|01|003002030")); verifyPosition(decoder, text( + "182043672999,010100001301,0,270613041652,166653,475341,3,0,355,6,2,1,231,8112432,23201,01,00,217,0,0,0,0,7"), + position("2013-06-27 04:16:52.000", true, 47.53410, 16.66530)); + + verifyPosition(decoder, text( "182043672999,010100001301,0,270613041652,166653,475341,3,0,355,6,2,1,231,8112432,23201,01,00,217,0,0,0,0,7")); - + } } diff --git a/test/org/traccar/protocol/Tk102ProtocolDecoderTest.java b/test/org/traccar/protocol/Tk102ProtocolDecoderTest.java index fd8033902..7d34d8383 100644 --- a/test/org/traccar/protocol/Tk102ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Tk102ProtocolDecoderTest.java @@ -10,7 +10,8 @@ public class Tk102ProtocolDecoderTest extends ProtocolDecoderTest { Tk102ProtocolDecoder decoder = new Tk102ProtocolDecoder(new Tk102Protocol()); - verifyNothing(decoder, text( "")); + verifyNothing(decoder, text( + "")); verifyNothing(decoder, text( "[!0000000081r(353327023367238,TK102-W998_01_V1.1.001_130219,255,001,255,001,0,100,100,0,internet,0000,0000,0,0,255,0,4,1,11,00)")); diff --git a/test/org/traccar/protocol/Tk103ProtocolDecoderTest.java b/test/org/traccar/protocol/Tk103ProtocolDecoderTest.java index 8f2cea217..d9152ecf0 100644 --- a/test/org/traccar/protocol/Tk103ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Tk103ProtocolDecoderTest.java @@ -10,6 +10,12 @@ public class Tk103ProtocolDecoderTest extends ProtocolDecoderTest { Tk103ProtocolDecoder decoder = new Tk103ProtocolDecoder(new Tk103Protocol()); + verifyAttributes(decoder, text( + "(013632651491,ZC20,040613,040137,6,42,112,0")); + + verifyAttributes(decoder, text( + "(864768010159785,ZC20,291015,030413,3,362,65535,255")); + verifyPosition(decoder, text( "(088047365460BR00151024A2555.3531S02855.3329E004.7055148276.1701000000L00009AA3)"), position("2015-10-24 05:51:48.000", true, -25.92255, 28.92222)); diff --git a/test/org/traccar/protocol/Tr20ProtocolDecoderTest.java b/test/org/traccar/protocol/Tr20ProtocolDecoderTest.java index 2bf504176..11d7847c2 100644 --- a/test/org/traccar/protocol/Tr20ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Tr20ProtocolDecoderTest.java @@ -10,7 +10,12 @@ public class Tr20ProtocolDecoderTest extends ProtocolDecoderTest { Tr20ProtocolDecoder decoder = new Tr20ProtocolDecoder(new Tr20Protocol()); - verifyNothing(decoder, text( "%%TRACKPRO01,1")); + verifyNothing(decoder, text( + "%%TRACKPRO01,1")); + + verifyPosition(decoder, text( + "%%TR-10,A,050916070549,N2240.8887E11359.2994,0,000,NA,D3800000,150,CFG:resend|"), + position("2005-09-16 07:05:49.000", true, 22.68148, 113.98832)); verifyPosition(decoder, text( "%%TR-10,A,050916070549,N2240.8887E11359.2994,0,000,NA,D3800000,150,CFG:resend|")); diff --git a/test/org/traccar/protocol/Tr900ProtocolDecoderTest.java b/test/org/traccar/protocol/Tr900ProtocolDecoderTest.java index 627b2296f..ddcacba1c 100644 --- a/test/org/traccar/protocol/Tr900ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Tr900ProtocolDecoderTest.java @@ -11,7 +11,8 @@ public class Tr900ProtocolDecoderTest extends ProtocolDecoderTest { Tr900ProtocolDecoder decoder = new Tr900ProtocolDecoder(new Tr900Protocol()); verifyPosition(decoder, text( - ">00001001,4,1,150626,131252,W05830.2978,S3137.2783,,00,348,18,00,003-000,0,3,11111011*3b!")); + ">00001001,4,1,150626,131252,W05830.2978,S3137.2783,,00,348,18,00,003-000,0,3,11111011*3b!"), + position("2015-06-26 13:12:52.000", true, -31.62131, -58.50496)); verifyPosition(decoder, text( ">12345678,1,1,070201,144111,W05829.2613,S3435.2313,,00,034,25,00,126-000,0,3,11111111*2d!")); diff --git a/test/org/traccar/protocol/TrackboxProtocolDecoderTest.java b/test/org/traccar/protocol/TrackboxProtocolDecoderTest.java index 08b17a130..697c1ff66 100644 --- a/test/org/traccar/protocol/TrackboxProtocolDecoderTest.java +++ b/test/org/traccar/protocol/TrackboxProtocolDecoderTest.java @@ -10,10 +10,12 @@ public class TrackboxProtocolDecoderTest extends ProtocolDecoderTest { TrackboxProtocolDecoder decoder = new TrackboxProtocolDecoder(new TrackboxProtocol()); - verifyNothing(decoder, text( "a=connect&v=11&i=111111111111111")); + verifyNothing(decoder, text( + "a=connect&v=11&i=111111111111111")); verifyPosition(decoder, text( - "183457.999,5126.0247N,00002.8686E,5.2,70.4,3,57.63,32.11,17.32,150507,05")); + "183457.999,5126.0247N,00002.8686E,5.2,70.4,3,57.63,32.11,17.32,150507,05"), + position("2007-05-15 18:34:57.999", true, 51.43375, 0.04781)); verifyPosition(decoder, text( "183558.999,5126.3979N,00003.0745E,5.2,70.4,3,57.63,32.11,17.32,150507,05")); diff --git a/test/org/traccar/protocol/TrvProtocolDecoderTest.java b/test/org/traccar/protocol/TrvProtocolDecoderTest.java new file mode 100644 index 000000000..a8e9fdb04 --- /dev/null +++ b/test/org/traccar/protocol/TrvProtocolDecoderTest.java @@ -0,0 +1,28 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolDecoderTest; + +public class TrvProtocolDecoderTest extends ProtocolDecoderTest { + + @Test + public void testDecode() throws Exception { + + TrvProtocolDecoder decoder = new TrvProtocolDecoder(new TrvProtocol()); + + verifyNothing(decoder, text( + "TRVAP00353456789012345")); + + verifyPosition(decoder, text( + "TRVAP01080524A2232.9806N11404.9355E000.1061830323.8706000908000102,460,0,9520,3671")); + + verifyPosition(decoder, text( + "TRVAP01080524A2232.9806N11404.9355E000.1061830323.8706000908000102,460,0,9520,3671"), + position("2008-05-24 06:18:30.000", true, 22.54968, 114.08226)); + + verifyPosition(decoder, text( + "TRVAP10080524A2232.9806N11404.9355E000.1061830323.8706000908000502,460,0,9520,3671,00,zh-cn,00")); + + } + +} diff --git a/test/org/traccar/protocol/UlbotechProtocolDecoderTest.java b/test/org/traccar/protocol/UlbotechProtocolDecoderTest.java index 7e321fa8e..30e040e3d 100644 --- a/test/org/traccar/protocol/UlbotechProtocolDecoderTest.java +++ b/test/org/traccar/protocol/UlbotechProtocolDecoderTest.java @@ -13,6 +13,9 @@ public class UlbotechProtocolDecoderTest extends ProtocolDecoderTest { UlbotechProtocolDecoder decoder = new UlbotechProtocolDecoder(new UlbotechProtocol()); verifyPosition(decoder, binary( + "f8010108679650230651689dc8e45b010e01194a26fbd47fa6001f003c0054030402420000040400024d7b0506037c18692212071131057f410c0ee0310d1b312f41413112ef0804000dd59fcc32f8")); + + verifyPosition(decoder, binary( "f8010103596580419465449da89d16010efe5580fe0923d82100140129005903040242000004040001a7f10506037818be220e070e31057b410c1324310d144131fa3208040020b1418297f8")); verifyPosition(decoder, binary( diff --git a/test/org/traccar/protocol/WatchProtocolDecoderTest.java b/test/org/traccar/protocol/WatchProtocolDecoderTest.java new file mode 100644 index 000000000..41af104dd --- /dev/null +++ b/test/org/traccar/protocol/WatchProtocolDecoderTest.java @@ -0,0 +1,37 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolDecoderTest; + +public class WatchProtocolDecoderTest extends ProtocolDecoderTest { + + @Test + public void testDecode() throws Exception { + + WatchProtocolDecoder decoder = new WatchProtocolDecoder(new WatchProtocol()); + + verifyPosition(decoder, text( + "[3G*4700186508*00B1*UD,301015,084840,V,45.853100,N,14.6224899,E,0.00,0.0,0.0,0,84,61,0,11,00000008,7,255,293,70,60,6453,139,60,6432,139,60,6431,132,60,6457,127,60,16353,126,60,6451,121,60,16352,118")); + + verifyNothing(decoder, text( + "[SG*8800000015*0002*LK")); + + verifyAttributes(decoder, text( + "[3G*4700186508*000B*LK,0,10,100")); + + verifyPosition(decoder, text( + "[SG*8800000015*0087*UD,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0000,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141"), + position("2014-04-22 13:46:52.000", true, 22.57171, 113.86140)); + + verifyPosition(decoder, text( + "[SG*8800000015*0087*UD,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0000,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141")); + + verifyPosition(decoder, text( + "[SG*8800000015*0088*UD2,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0000,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141")); + + verifyPosition(decoder, text( + "[SG*8800000015*0087*AL,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0001,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141")); + + } + +} diff --git a/test/org/traccar/protocol/WondexProtocolDecoderTest.java b/test/org/traccar/protocol/WondexProtocolDecoderTest.java index 5173734a8..e5685033c 100644 --- a/test/org/traccar/protocol/WondexProtocolDecoderTest.java +++ b/test/org/traccar/protocol/WondexProtocolDecoderTest.java @@ -9,6 +9,20 @@ public class WondexProtocolDecoderTest extends ProtocolDecoderTest { public void testDecode() throws Exception { WondexProtocolDecoder decoder = new WondexProtocolDecoder(new WondexProtocol()); + + verifyPosition(decoder, text( + "2000000108,20151030145404,76.948633,43.354700,0,140,15,100,1,1325,125.4,10.5,0.0"), + position("2015-10-30 14:54:04.000", true, 43.35470, 76.94863)); + + verifyPosition(decoder, text( + "2000000257,20151030145351,69.379976,53.283905,0,0,16,2,0,0,469.1,58.9,0.0"), + position("2015-10-30 14:53:51.000", false, 53.28390, 69.37998)); + + verifyPosition(decoder, text( + "2000000232,20151030145206,51.166900,43.651353,0,132,11,2,0,0,0.0,0.0,0.0")); + + verifyPosition(decoder, text( + "2000000259,20151030145653,69.380826,53.283890,9,10,15,2,1,695,1002.6,108.2,0.0")); verifyPosition(decoder, text( "1044989601,20130323074605,0.000000,90.000000,0,000,0,0,2")); diff --git a/tools/test-generator.py b/tools/test-generator.py new file mode 100755 index 000000000..681d1755d --- /dev/null +++ b/tools/test-generator.py @@ -0,0 +1,55 @@ +#!/usr/bin/python + +import sys +import math +import urllib +import urllib2 +import time + +id = '123456789012345' +server = 'http://localhost:5055' +period = 1 +step = 0.001 + +waypoints = [ + (40.722412, -74.006288), + (40.728592, -74.005258), + (40.728348, -74.002822), + (40.725437, -73.996750), + (40.721778, -73.999818), + (40.723323, -74.002994) +] + +points = [] + +for i in range(0, len(waypoints)): + (lat1, lon1) = waypoints[i] + (lat2, lon2) = waypoints[(i + 1) % len(waypoints)] + length = math.sqrt((lat2 - lat1) ** 2 + (lon2 - lon1) ** 2) + count = int(math.ceil(length / step)) + for j in range(0, count): + lat = lat1 + (lat2 - lat1) * j / count + lon = lon1 + (lon2 - lon1) * j / count + points.append((lat, lon)) + +def send(lat, lon, course): + params = (('id', id), ('timestamp', int(time.time())), ('lat', lat), ('lon', lon), ('bearing', course)) + urllib2.urlopen(server + '?' + urllib.urlencode(params)).read() + +def course(lat1, lon1, lat2, lon2): + lat1 = lat1 * math.pi / 180 + lon1 = lon1 * math.pi / 180 + lat2 = lat2 * math.pi / 180 + lon2 = lon2 * math.pi / 180 + y = math.sin(lon2 - lon1) * math.cos(lat2) + x = math.cos(lat1) * math.sin(lat2) - math.sin(lat1) * math.cos(lat2) * math.cos(lon2 - lon1) + return (math.atan2(y, x) % (2 * math.pi)) * 180 / math.pi + +index = 0 + +while True: + (lat1, lon1) = points[index % len(points)] + (lat2, lon2) = points[(index + 1) % len(points)] + send(lat1, lon1, course(lat1, lon1, lat2, lon2)) + time.sleep(period) + index += 1 diff --git a/tools/test-integration.py b/tools/test-integration.py index 64abc9ffe..2a332ba7d 100755 --- a/tools/test-integration.py +++ b/tools/test-integration.py @@ -21,7 +21,6 @@ messages = { 'suntech' : 'SA200STT;123456;042;20120101;12:11:00;16d41;-15.618767;-056.083214;000.011;000.00;11;1;41557;12.21;000000;1;3205\r', 'h02' : '*HQ,123456789012345,V1,121300,A,6000.0000,N,13000.0000,E,0.00,0.00,010112,ffffffff,000000,000000,000000,000000#', 'jt600' : '$\x00\x00\x12\x34\x56\x11\x00\x1B\x01\x01\x12\x12\x14\x00\x60\x00\x00\x00\x13\x00\x00\x00\x0F\x00\x00\x07\x50\x00\x00\x00\x2B\x91\x04\x4D\x1F\xA1', - 'ev603' : '!1,123456789012345;!A,01/01/12,12:15:00,60.000000,130.000000,0.0,25101,0;', 'v680' : '#123456789012345#1000#0#1000#AUT#1#66830FFB#13000.0000,E,6000.0000,N,001.41,259#010112#121600##', 'pt502' : '$POS,123456,121700.000,A,6000.0000,N,13000.0000,E,0.0,0.0,010112,,,A/00000,00000/0/23895000//\r\n', 'tr20' : '%%123456789012345,A,120101121800,N6000.0000E13000.0000,0,000,0,01034802,150,[Message]\r\n', @@ -41,7 +40,28 @@ messages = { 'pt3000' : '%123456789012345,$GPRMC,124500.000,A,6000.0000,N,13000.0000,E,0.00,,010112,,,A,+100000000000,N098d', 'topflytech' : '(123456789012345BP00XG00b600000000L00074b54S00000000R0C0F0014000100f0120101124700A6000.0000N13000.0000E000.0000.00)', 'laipac' : '$AVRMC,123456789012345,124800,a,6000.0000,N,13000.0000,E,0.00,0.00,010112,0,3.727,17,1,0,0*17\r\n', - 'gotop' : '#123456789012345,CMD-T,A,DATE:120101,TIME:125000,LAT:60.0000000N,LOT:130.0000000E,Speed:000.0,84-20,000#' + 'gotop' : '#123456789012345,CMD-T,A,DATE:120101,TIME:125000,LAT:60.0000000N,LOT:130.0000000E,Speed:000.0,84-20,000#', + 'sanav' : 'imei:123456789012345rmc:$GPRMC,093604.354,A,4735.0862,N,01905.2146,E,0.00,0.00,171013,,*09,AUTO-4103mv', + 'easytrack' : '*ET,123456789012345,DW,A,0A090D,101C0D,00CF27C6,0413FA4E,0000,0000,00000000,20,4,0000,00F123#', + 'gpsmarker' : '$GM200123456789012345T100511123300N55516789E03756123400000035230298#\r', + 'stl060' : '$1,123456789012345,D001,AP29AW0963,23/02/14,14:06:54,17248488N,078342226E,0.08,193.12,1,1,1,1,1,A#', + 'cartrack' : '$$123456????????&A9955&B102904.000,A,2233.0655,N,11404.9440,E,0.00,,030109,,*17|6.3|&C0100000100&D000024?>&E10000000##', + 'minifinder' : '!1,123456789012345;!A,01/01/12,12:15:00,60.000000,130.000000,0.0,25101,0;', + 'haicom' : '$GPRS123456789012345,T100001,150618,230031,5402267400332464,0004,2014,000001,,,1,00#V040*', + 'box' : 'H,BT,123456789012345,081028142432,F5813D19,6D6E6DC2\rL,081028142429,G,52.51084,-1.70849,0,170,0,1,0\r', + 'freedom' : 'IMEI,123456789012345,2014/05/22, 20:49:32, N, Lat:4725.9624, E, Lon:01912.5483, Spd:5.05\r\n', + 'telik' : '182012345699,010100001301,0,270613041652,166653,475341,3,0,355,6,2,1,231,8112432,23201,01,00,217,0,0,0,0,7\0', + 'trackbox' : 'a=connect&v=11&i=123456789012345\r\n183457.999,5126.0247N,00002.8686E,5.2,70.4,3,57.63,32.11,17.32,150507,05\r\n', + 'visiontek' : '$1,AP09BU9397,123456789012345,20,06,14,15,03,28,17267339N,078279407E,060.0,073,0550,11,0,1,0,0,1,1,26,A,0000000000#', + 'tr900' : '>123456,4,1,150626,131252,W05830.2978,S3137.2783,,00,348,18,00,003-000,0,3,11111011*3b!\r\n', + 'ardi01' : '123456789012345,20141010052719,24.4736042,56.8445807,110,289,40,7,5,78,-1\r\n', + 'xt013' : 'TK,123456789012345,150131090859,+53.267863,+5.767363,0,38,12,0,F,204,08,C94,336C,24,,4.09,1,,,,,,,,\r\n', + 'gosafe' : '*GS16,123456789012345,100356130215,,SYS:G79W;V1.06;V1.0.2,GPS:A;6;N24.802700;E46.616828;0;0;684;1.35,COT:60,ADC:4.31;0.10,DTT:20000;;0;0;0;1#', + 'xirgo' : '$$123456789012345,6001,2013/01/22,15:36:18,25.80907,-80.32531,7.1,19,165.2,11,0.8,11.1,17,1,1,3.9,2##', + 'mtx' : '#MTX,123456789012345,20101226,195550,41.6296399,002.3611174,000,035,000000.00,X,X,1111,000,0,0\r\n', + 'aquila' : '$$SRINI_1MS,123456,1,12.963515,77.533844,150925161628,A,27,0,8,0,68,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,*43\r\n', + 'flextrack' : '-1,LOGON,123456,8945000000\r-2,UNITSTAT,20060101,123442,1080424008,N0.00.0000,E0.00.0000,0,0,0,4129,-61,2,23866,0,999,A214,63,2EE2,3471676\r', + 'watch' : '[SG*123456*0087*UD,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0000,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141]' } baseUrl = 'http://localhost:8082' @@ -132,7 +152,7 @@ print 'Covered: %d' % len(protocols) for protocol in messages: send_message(ports[protocol], messages[protocol]) -time.sleep(5) +time.sleep(10) for device in devices: protocols -= set(get_protocols(cookie, devices[device])) diff --git a/tools/test-performance.py b/tools/test-performance.py new file mode 100755 index 000000000..ec31e9b86 --- /dev/null +++ b/tools/test-performance.py @@ -0,0 +1,44 @@ +#!/usr/bin/python3 + +import asyncio +import random + +host = 'localhost' +port = 5027 + +messageLogin = bytearray.fromhex('000F313233343536373839303132333435') +messageLocation = bytearray.fromhex('000000000000002b080100000140d4e3ec6e000cc661d01674a5e0fffc00000900000004020100f0000242322318000000000100007a04') + +devices = 100 +period = 1 + + +class AsyncClient(asyncio.Protocol): + + def __init__(self, loop): + self.loop = loop + self.buffer = memoryview(messageLogin) + + def connection_made(self, transport): + self.send_message(transport) + + def send_message(self, transport): + transport.write(self.buffer) + self.buffer = memoryview(messageLocation) + delay = period * (0.9 + 0.2 * random.random()) + self.loop.call_later(delay, self.send_message, transport) + + def data_received(self, data): + pass + + def connection_lost(self, exc): + self.loop.stop() + + +loop = asyncio.get_event_loop() + +for i in range(0, devices): + loop.create_task(loop.create_connection(lambda: AsyncClient(loop), host, port)) + +loop.run_forever() +loop.close() diff --git a/tools/translate.py b/tools/translate.py index fd7d139df..e8324a61a 100755 --- a/tools/translate.py +++ b/tools/translate.py @@ -1,41 +1,35 @@ #!/usr/bin/python -import re import os +import optparse +import urllib2 +import json +import base64 -abspath = os.path.abspath(__file__) -dname = os.path.dirname(abspath) -os.chdir(dname) +parser = optparse.OptionParser() +parser.add_option("-u", "--user", dest="username", help="transifex user login") +parser.add_option("-p", "--password", dest="password", help="transifex user password") -path = '../web/l10n/' +(options, args) = parser.parse_args() -files = [f for f in os.listdir(path) if os.path.isfile(path + f) and f.endswith('.js') and not f.endswith('en.js')] -for f in files: - f = path + f +if not options.username or not options.password: + parser.error('User name and password are required') - print 'en -> ' + f[-5:-3] +os.chdir(os.path.dirname(os.path.abspath(__file__))) - dict = {} +path = "../web/l10n/" - for line in open(f).read().splitlines(): - match = re.search(" (\\w+): '(.+)'(,)?", line) - if match: - dict[match.group(1)] = match.group(2) +def request(url): + req = urllib2.Request(url) + auth = base64.encodestring("%s:%s" % (options.username, options.password)).replace("\n", "") + req.add_header("Authorization", "Basic %s" % auth) + return urllib2.urlopen(req) - out = open(f, 'w') +resource = json.load(request("https://www.transifex.com/api/2/project/traccar/resource/web/?details")) - for line in open(path + 'en.js').read().splitlines(): - match = re.search(" (\\w+): '(.+)'(,)?", line) - if match: - if dict.has_key(match.group(1)): - value = dict[match.group(1)] - else: - print '"' + match.group(2) + '"' - value = match.group(2) + ' (*)' - - out.write(' ' + match.group(1) + ": '" + value + "'") - if match.group(3) is not None: - out.write(',') - out.write('\n') - else: - out.write(line + '\n') +for language in resource["available_languages"]: + code = language["code"] + data = request("https://www.transifex.com/api/2/project/traccar/resource/web/translation/" + code + "?file") + file = open(path + code + ".json", "wb") + file.write(data.read()) + file.close() diff --git a/web/.jscsrc b/web/.jscsrc index 7d924ab96..dda6932e1 100644 --- a/web/.jscsrc +++ b/web/.jscsrc @@ -1,4 +1,5 @@ { "preset": "crockford", - "maxErrors": 100 + "maxErrors": 100, + "excludeFiles": ["arrowstyle.js"] } diff --git a/web/.jshintignore b/web/.jshintignore index d057f1b54..1c48d68e2 100644 --- a/web/.jshintignore +++ b/web/.jshintignore @@ -1,3 +1,4 @@ l10n/** tests/** locale.js +arrowstyle.js diff --git a/web/app/Application.js b/web/app/Application.js index 83ca9e860..ebf685dbc 100644 --- a/web/app/Application.js +++ b/web/app/Application.js @@ -86,14 +86,16 @@ Ext.define('Traccar.Application', { if (!result.success) { Ext.Msg.alert(Strings.errorTitle, result.error); } - handler.call(scope, options, success, response); + if (handler) { + handler.call(scope, options, success, response); + } } else { if (response.statusText) { Ext.Msg.alert(Strings.errorTitle, response.statusText); } else { - Ext.Msg.alert(Strings.errorTitle, response.status.toString()); // TODO: text message + Ext.Msg.alert(Strings.errorTitle, Strings.errorConnection); } } - } + }; } }); diff --git a/web/app/AttributeFormatter.js b/web/app/AttributeFormatter.js index b7b2d01a6..44cc7d5a8 100644 --- a/web/app/AttributeFormatter.js +++ b/web/app/AttributeFormatter.js @@ -36,7 +36,7 @@ Ext.define('Traccar.AttributeFormatter', { defaultFormatter: function (value) { if (typeof value === 'number') { - return value.toFixed(2); + return Number(value.toFixed(2)); } else if (typeof value === 'boolean') { return value ? Ext.Msg.buttonText.yes : Ext.Msg.buttonText.no; } else if (value instanceof Date) { diff --git a/web/app/Style.js b/web/app/Style.js index 4c7028658..58ab059ad 100644 --- a/web/app/Style.js +++ b/web/app/Style.js @@ -24,6 +24,7 @@ Ext.define('Traccar.Style', { dateTimeFormat: 'Y-m-d H:i:s', timeFormat: 'H:i', + dateFormat: 'Y-m-d', weekStartDay: 1, deviceWidth: 350, @@ -35,15 +36,26 @@ Ext.define('Traccar.Style', { mapDefaultLon: -0.1275, mapDefaultZoom: 6, - mapMaxZoom: 19, - mapSelectColor: 'rgba(0, 255, 0, 1.0)', - mapSelectRadius: 10, - mapReportColor: 'rgba(0, 0, 255, 1.0)', - mapReportRadius: 5, - mapLiveColor: 'rgba(255, 0, 0, 1.0)', - mapLiveRadius: 7, - mapStrokeColor: 'rgba(50, 50, 50, 1.0)', + mapRouteColor: 'rgba(21, 127, 204, 1.0)', mapRouteWidth: 5, - mapMarkerStroke: 2, + + mapArrowStrokeColor: 'rgba(50, 50, 50, 1.0)', + mapArrowStrokeWidth: 2, + + mapTextColor: 'rgba(50, 50, 50, 1.0)', + mapTextStrokeColor: 'rgba(255, 255, 255, 1.0)', + mapTextStrokeWidth: 2, + mapTextOffset: 10, + mapTextFont: 'bold 12px sans-serif', + + mapColorOnline: '#4DFA90', + mapColorUnknown: '#FABE4D', + mapColorOffline: '#FF5468', + mapColorReport: 'rgba(21, 127, 204, 1.0)', + + mapRadiusNormal: 10, + mapRadiusSelected: 15, + + mapMaxZoom: 19, mapDelay: 500 }); diff --git a/web/app/controller/Root.js b/web/app/controller/Root.js index b4ab06b82..79827b8a6 100644 --- a/web/app/controller/Root.js +++ b/web/app/controller/Root.js @@ -85,5 +85,33 @@ Ext.define('Traccar.controller.Root', { } else { Ext.create('widget.main'); } + this.asyncUpdate(true); + }, + + asyncUpdate: function (first) { + Ext.Ajax.request({ + scope: this, + url: '/api/async', + params: { + first: first + }, + callback: Traccar.app.getErrorHandler(this, function (options, success, response) { + var i, store, data, position; + if (success) { + store = Ext.getStore('LatestPositions'); + data = Ext.decode(response.responseText).data; + + for (i = 0; i < data.length; i++) { + position = store.findRecord('deviceId', data[i].deviceId, 0, false, false, true); + if (position) { + position.set(data[i]); + } else { + store.add(Ext.create('Traccar.model.Position', data[i])); + } + } + this.asyncUpdate(false); + } + }) + }); } }); diff --git a/web/app/store/DistanceUnits.js b/web/app/store/DistanceUnits.js index 20d057c1f..7f808c684 100644 --- a/web/app/store/DistanceUnits.js +++ b/web/app/store/DistanceUnits.js @@ -32,7 +32,7 @@ Ext.define('Traccar.store.DistanceUnits', { var model; if (unit) { model = this.findRecord('key', unit); - return (value * model.get('factor')).toFixed(2) + ' ' + model.get('name'); + return (value * Number(model.get('factor')).toFixed(2)) + ' ' + model.get('name'); } else { return value; } diff --git a/web/app/store/SpeedUnits.js b/web/app/store/SpeedUnits.js index d02892a01..cbcf94e3b 100644 --- a/web/app/store/SpeedUnits.js +++ b/web/app/store/SpeedUnits.js @@ -32,7 +32,7 @@ Ext.define('Traccar.store.SpeedUnits', { var model; if (unit) { model = this.findRecord('key', unit); - return (value * model.get('factor')).toFixed(1) + ' ' + model.get('name'); + return (value * Number(model.get('factor')).toFixed(1)) + ' ' + model.get('name'); } else { return value; } diff --git a/web/app/view/DevicesController.js b/web/app/view/DevicesController.js index dd3ca5a05..c29854d12 100644 --- a/web/app/view/DevicesController.js +++ b/web/app/view/DevicesController.js @@ -27,6 +27,7 @@ Ext.define('Traccar.view.DevicesController', { listen: { controller: { '*': { + selectDevice: 'selectDevice', selectReport: 'selectReport' } } @@ -87,10 +88,14 @@ Ext.define('Traccar.view.DevicesController', { this.lookupReference('toolbarRemoveButton').setDisabled(empty); this.lookupReference('deviceCommandButton').setDisabled(empty); if (!empty) { - this.fireEvent('selectDevice', selected.getLastSelected()); + this.fireEvent('selectDevice', selected.getLastSelected(), true); } }, + selectDevice: function (device, center) { + this.getView().getSelectionModel().select([device], false, true); + }, + selectReport: function (position) { if (position !== undefined) { this.getView().getSelectionModel().deselectAll(); diff --git a/web/app/view/Login.js b/web/app/view/Login.js index a4a68843d..14a3fa41f 100644 --- a/web/app/view/Login.js +++ b/web/app/view/Login.js @@ -24,6 +24,7 @@ Ext.define('Traccar.view.Login', { controller: 'login', + title: Strings.loginTitle, closable: false, modal: false, @@ -33,8 +34,8 @@ Ext.define('Traccar.view.Login', { autoEl: { tag: 'form', - method: 'POST', - action: 'blank', + method: 'GET', + action: 'favicon.ico', target: 'submitTarget' }, diff --git a/web/app/view/LoginController.js b/web/app/view/LoginController.js index e0dbcce88..0b2090ffb 100644 --- a/web/app/view/LoginController.js +++ b/web/app/view/LoginController.js @@ -48,7 +48,6 @@ Ext.define('Traccar.view.LoginController', { Traccar.ErrorManager.error(Strings.loginFailed); } } - } }); } @@ -65,12 +64,13 @@ Ext.define('Traccar.view.LoginController', { }, onSelectLanguage: function (selected) { - var paramName = 'locale'; - var paramValue = selected.getValue(); - var url = window.location.href; + var paramName, paramValue, url, prefix, suffix; + paramName = 'locale'; + paramValue = selected.getValue(); + url = window.location.href; if (url.indexOf(paramName + '=') >= 0) { - var prefix = url.substring(0, url.indexOf(paramName)); - var suffix = url.substring(url.indexOf(paramName)); + prefix = url.substring(0, url.indexOf(paramName)); + suffix = url.substring(url.indexOf(paramName)); suffix = suffix.substring(suffix.indexOf('=') + 1); suffix = (suffix.indexOf('&') >= 0) ? suffix.substring(suffix.indexOf('&')) : ''; url = prefix + paramName + '=' + paramValue + suffix; diff --git a/web/app/view/Map.js b/web/app/view/Map.js index 9a032e79f..7d81699a3 100644 --- a/web/app/view/Map.js +++ b/web/app/view/Map.js @@ -27,9 +27,21 @@ Ext.define('Traccar.view.Map', { title: Strings.mapTitle, layout: 'fit', + getMap: function () { + return this.map; + }, + + getMapView: function () { + return this.mapView; + }, + + getVectorSource: function () { + return this.vectorSource; + }, + listeners: { afterrender: function () { - var user, server, layer, type, bingKey, vectorLayer, lat, lon, zoom; + var user, server, layer, type, bingKey, vectorLayer, lat, lon, zoom, target; user = Traccar.app.getUser(); server = Traccar.app.getServer(); @@ -40,7 +52,10 @@ Ext.define('Traccar.view.Map', { if (type === 'custom') { layer = new ol.layer.Tile({ source: new ol.source.XYZ({ - url: server.get('mapUrl') + url: server.get('mapUrl'), + attributions: [new ol.Attribution({ + html: '' + })] }) }); } else if (type === 'bingRoad') { @@ -83,6 +98,28 @@ Ext.define('Traccar.view.Map', { layers: [layer, vectorLayer], view: this.mapView }); + + target = this.map.getTarget(); + if (typeof target === 'string') { + target = Ext.get(target).dom; + } + + this.map.on('pointermove', function (e) { + var hit = this.forEachFeatureAtPixel(e.pixel, function (feature, layer) { + return true; + }); + if (hit) { + target.style.cursor = 'pointer'; + } else { + target.style.cursor = ''; + } + }); + + this.map.on('click', function (e) { + this.map.forEachFeatureAtPixel(e.pixel, function (feature, layer) { + this.fireEvent('selectFeature', feature); + }, this); + }, this); }, resize: function () { diff --git a/web/app/view/MapController.js b/web/app/view/MapController.js index b53e46671..c153ebd45 100644 --- a/web/app/view/MapController.js +++ b/web/app/view/MapController.js @@ -22,197 +22,214 @@ Ext.define('Traccar.view.MapController', { listen: { controller: { '*': { - reportShow: 'reportShow', - reportClear: 'reportClear', selectDevice: 'selectDevice', selectReport: 'selectReport' } + }, + store: { + '#LatestPositions': { + add: 'updateLatest', + update: 'updateLatest' + }, + '#Positions': { + load: 'loadReport', + clear: 'clearReport' + } + }, + component: { + '#': { + selectFeature: 'selectFeature' + } } } }, init: function () { - this.liveData = {}; - this.update(true); + this.latestMarkers = {}; + this.reportMarkers = {}; }, - update: function (first) { - Ext.Ajax.request({ - scope: this, - url: '/api/async', - params: { - first: first - }, - success: function (response) { - var data = Ext.decode(response.responseText).data; - - var i; - for (i = 0; i < data.length; i++) { - - var store = Ext.getStore('LatestPositions'); - var deviceStore = Ext.getStore('Devices'); - - var found = store.query('deviceId', data[i].deviceId); - if (found.getCount() > 0) { - found.first().set(data[i]); - } else { - store.add(Ext.create('Traccar.model.Position', data[i])); - } - - var geometry = new ol.geom.Point(ol.proj.fromLonLat([ - data[i].longitude, - data[i].latitude - ])); - - if (data[i].deviceId in this.liveData) { - this.liveData[data[i].deviceId].setGeometry(geometry); - } else { - var name = deviceStore.query('id', data[i].deviceId).first().get('name'); - - var style = this.getMarkerStyle(Traccar.Style.mapLiveRadius, Traccar.Style.mapLiveColor, data[i].course, name); - var marker = new ol.Feature({ - geometry: geometry, - originalStyle: style - }); - marker.setStyle(style); - this.getView().vectorSource.addFeature(marker); - this.liveData[data[i].deviceId] = marker; - } - } + updateLatest: function (store, data) { + var i, position, geometry, device, deviceId, marker, style; - this.update(false); - }, - failure: function () { - // TODO: error + if (!Ext.isArray(data)) { + data = [data]; + } + + for (i = 0; i < data.length; i++) { + position = data[i]; + deviceId = position.get('deviceId'); + device = Ext.getStore('Devices').findRecord('id', deviceId, 0, false, false, true); + + geometry = new ol.geom.Point(ol.proj.fromLonLat([ + position.get('longitude'), + position.get('latitude') + ])); + + if (deviceId in this.latestMarkers) { + marker = this.latestMarkers[deviceId]; + marker.setGeometry(geometry); + } else { + marker = new ol.Feature(geometry); + marker.set('record', device); + this.latestMarkers[deviceId] = marker; + this.getView().getVectorSource().addFeature(marker); + + style = this.getLatestMarker(); + style.getText().setText(device.get('name')); + marker.setStyle(style); } + + marker.getStyle().getImage().setRotation(position.get('course') * Math.PI / 180); + } + }, + + loadReport: function (store, data) { + var i, position, point, geometry, marker, style; + + this.clearReport(store); + + this.reportRoute = new ol.Feature({ + geometry: new ol.geom.LineString([]) }); + this.reportRoute.setStyle(this.getRouteStyle()); + this.getView().getVectorSource().addFeature(this.reportRoute); + + for (i = 0; i < data.length; i++) { + position = data[i]; + + point = ol.proj.fromLonLat([ + position.get('longitude'), + position.get('latitude') + ]); + geometry = new ol.geom.Point(point); + + marker = new ol.Feature(geometry); + marker.set('record', position); + this.reportMarkers[position.get('id')] = marker; + this.getView().getVectorSource().addFeature(marker); + + style = this.getReportMarker(); + style.getImage().setRotation(position.get('course') * Math.PI / 180); + style.getText().setText( + Ext.Date.format(position.get('fixTime'), Traccar.Style.dateTimeFormat)); + + marker.setStyle(style); + + this.reportRoute.getGeometry().appendCoordinate(point); + } }, - getLineStyle: function () { + clearReport: function (store) { + var vectorSource, key; + vectorSource = this.getView().getVectorSource(); + + if (this.reportRoute) { + vectorSource.removeFeature(this.reportRoute); + this.reportRoute = null; + } + + if (this.reportMarkers) { + for (key in this.reportMarkers) { + if (this.reportMarkers.hasOwnProperty(key)) { + vectorSource.removeFeature(this.reportMarkers[key]); + } + } + this.reportMarkers = {}; + } + }, + + getRouteStyle: function () { return new ol.style.Style({ stroke: new ol.style.Stroke({ - color: Traccar.Style.mapStrokeColor, + color: Traccar.Style.mapRouteColor, width: Traccar.Style.mapRouteWidth }) }); }, - getMarkerStyle: function (radius, color, rotation, text) { + getMarkerStyle: function (radius, color) { return new ol.style.Style({ - image: new ol.style.RegularShape({ - points: 3, + image: new ol.style.Arrow({ radius: radius, fill: new ol.style.Fill({ color: color }), stroke: new ol.style.Stroke({ - color: Traccar.Style.mapStrokeColor, - width: Traccar.Style.mapMarkerStroke - }), - rotation: rotation * Math.PI / 180 + color: Traccar.Style.mapArrowStrokeColor, + width: Traccar.Style.mapArrowStrokeWidth + }) }), text: new ol.style.Text({ textBaseline: 'bottom', - text: text, fill: new ol.style.Fill({ - color: '#000' + color: Traccar.Style.mapTextColor }), stroke: new ol.style.Stroke({ - color: '#FFF', - width: 2 + color: Traccar.Style.mapTextStrokeColor, + width: Traccar.Style.mapTextStrokeWidth }), - offsetY: -12, - font : 'bold 12px sans-serif' + offsetY: -radius / 2 - Traccar.Style.mapTextOffset, + font : Traccar.Style.mapTextFont }) }); }, - reportShow: function () { - this.reportClear(); - - var vectorSource = this.getView().vectorSource; - - var data = Ext.getStore('Positions').getData(); - - var index; - var positions = []; - this.reportRoutePoints = {}; + getLatestMarker: function () { + return this.getMarkerStyle( + Traccar.Style.mapRadiusNormal, Traccar.Style.mapColorUnknown); + }, - for (index = 0; index < data.getCount(); index++) { - var point = ol.proj.fromLonLat([ - data.getAt(index).data.longitude, - data.getAt(index).data.latitude - ]); - positions.push(point); - - var style = this.getMarkerStyle(Traccar.Style.mapReportRadius, Traccar.Style.mapReportColor, data.getAt(index).data.course); - var feature = new ol.Feature({ - geometry: new ol.geom.Point(positions[index]), - originalStyle: style - }); - feature.setStyle(style); - this.reportRoutePoints[data.getAt(index).get('id')] = feature; - } + getReportMarker: function () { + return this.getMarkerStyle( + Traccar.Style.mapRadiusNormal, Traccar.Style.mapColorReport); + }, - this.reportRoute = new ol.Feature({ - geometry: new ol.geom.LineString(positions) + resizeMarker: function (style, radius) { + return new ol.style.Style({ + image: new ol.style.Arrow({ + radius: radius, + fill: style.getImage().getFill(), + stroke: style.getImage().getStroke(), + rotation: style.getImage().getRotation() + }), + text: style.getText() }); - this.reportRoute.setStyle(this.getLineStyle()); - vectorSource.addFeature(this.reportRoute); - - for (var key in this.reportRoutePoints) { - if (this.reportRoutePoints.hasOwnProperty(key)) { - vectorSource.addFeature(this.reportRoutePoints[key]); - } - } }, - reportClear: function () { - var vectorSource = this.getView().vectorSource; - - if (this.reportRoute !== undefined) { - vectorSource.removeFeature(this.reportRoute); - this.reportRoute = undefined; + selectMarker: function (marker, center) { + if (this.selectedMarker) { + this.selectedMarker.setStyle( + this.resizeMarker(this.selectedMarker.getStyle(), Traccar.Style.mapRadiusNormal)); } - if (this.reportRoutePoints !== undefined) { - for (var key in this.reportRoutePoints) { - if (this.reportRoutePoints.hasOwnProperty(key)) { - vectorSource.removeFeature(this.reportRoutePoints[key]); - } + if (marker) { + marker.setStyle( + this.resizeMarker(marker.getStyle(), Traccar.Style.mapRadiusSelected)); + if (center) { + this.getView().getMapView().setCenter(marker.getGeometry().getCoordinates()); } - this.reportRoutePoints = {}; - } - }, - - selectPosition: function (feature) { - if (this.currentFeature !== undefined) { - this.currentFeature.setStyle(this.currentFeature.get('originalStyle')); } - if (feature !== undefined) { - var name = feature.getStyle().getText().getText(); - feature.setStyle(this.getMarkerStyle(Traccar.Style.mapSelectRadius, Traccar.Style.mapSelectColor, 0, name)); - - var pan = ol.animation.pan({ - duration: Traccar.Style.mapDelay, - source: this.getView().mapView.getCenter() - }); - this.getView().map.beforeRender(pan); - this.getView().mapView.setCenter(feature.getGeometry().getCoordinates()); - } + this.selectedMarker = marker; + }, - this.currentFeature = feature; + selectDevice: function (device, center) { + this.selectMarker(this.latestMarkers[device.get('id')], center); }, - selectDevice: function (device) { - this.selectPosition(this.liveData[device.get('id')]); + selectReport: function (position, center) { + this.selectMarker(this.reportMarkers[position.get('id')], center); }, - selectReport: function (position) { - if (this.reportRoutePoints[position.get('id')] !== undefined) { - this.selectPosition(this.reportRoutePoints[position.get('id')]); + selectFeature: function (feature) { + var record = feature.get('record'); + if (record) { + if (record instanceof Traccar.model.Device) { + this.fireEvent('selectDevice', record, false); + } else { + this.fireEvent('selectReport', record, false); + } } } - }); diff --git a/web/app/view/Register.js b/web/app/view/Register.js index 445f335f9..7c2881d62 100644 --- a/web/app/view/Register.js +++ b/web/app/view/Register.js @@ -23,6 +23,8 @@ Ext.define('Traccar.view.Register', { controller: 'register', + title: Strings.loginRegister, + items: { xtype: 'form', reference: 'form', diff --git a/web/app/view/Report.js b/web/app/view/Report.js index 6f2359253..91ccba917 100644 --- a/web/app/view/Report.js +++ b/web/app/view/Report.js @@ -45,6 +45,7 @@ Ext.define('Traccar.view.Report', { xtype: 'datefield', reference: 'fromDateField', startDay: Traccar.Style.weekStartDay, + format: Traccar.Style.dateFormat, value: new Date(new Date().getTime() - 30 * 60 * 1000) }, { xtype: 'timefield', @@ -59,6 +60,7 @@ Ext.define('Traccar.view.Report', { xtype: 'datefield', reference: 'toDateField', startDay: Traccar.Style.weekStartDay, + format: Traccar.Style.dateFormat, value: new Date() }, { xtype: 'timefield', @@ -84,7 +86,7 @@ Ext.define('Traccar.view.Report', { flex: 1, renderer: Traccar.AttributeFormatter.getFormatter('valid') }, { - text: Strings.positionTime, + text: Strings.positionFixTime, dataIndex: 'fixTime', flex: 1, xtype: 'datecolumn', diff --git a/web/app/view/ReportController.js b/web/app/view/ReportController.js index 2badfea63..9c2abcc71 100644 --- a/web/app/view/ReportController.js +++ b/web/app/view/ReportController.js @@ -22,7 +22,8 @@ Ext.define('Traccar.view.ReportController', { listen: { controller: { '*': { - selectDevice: 'selectDevice' + selectDevice: 'selectDevice', + selectReport: 'selectReport' } } } @@ -53,28 +54,27 @@ Ext.define('Traccar.view.ReportController', { deviceId: deviceId, from: from.toISOString(), to: to.toISOString() - }, - scope: this, - callback: function () { - this.fireEvent('reportShow'); } }); }, onClearClick: function () { Ext.getStore('Positions').removeAll(); - this.fireEvent('reportClear'); }, onSelectionChange: function (selected) { if (selected.getCount() > 0) { - this.fireEvent('selectReport', selected.getLastSelected()); + this.fireEvent('selectReport', selected.getLastSelected(), true); } }, selectDevice: function (device) { - if (device !== undefined) { + if (device) { this.getView().getSelectionModel().deselectAll(); } + }, + + selectReport: function (position, center) { + this.getView().getSelectionModel().select([position], false, true); } }); diff --git a/web/app/view/StateController.js b/web/app/view/StateController.js index 29f6a7c6d..01df6645d 100644 --- a/web/app/view/StateController.js +++ b/web/app/view/StateController.js @@ -25,58 +25,49 @@ Ext.define('Traccar.view.StateController', { selectDevice: 'selectDevice', selectReport: 'selectReport' } + }, + store: { + '#LatestPositions': { + add: 'updateLatest', + update: 'updateLatest' + }, + '#Positions': { + clear: 'clearReport' + } } } }, - init: function () { - var store = Ext.getStore('LatestPositions'); - store.on('add', this.add, this); - store.on('update', this.update, this); - }, + keys: (function () { + var i, list, result; + result = {}; + list = ['fixTime', 'latitude', 'longitude', 'valid', 'altitude', 'speed', 'course', 'address', 'protocol']; + for (i = 0; i < list.length; i++) { + result[list[i]] = { + priority: i, + name: Strings['position' + list[i].replace(/^\w/g, function (s) { + return s.toUpperCase(); + })] + }; + } + return result; + }()), - keys: { - fixTime: { - priority: 1, - name: Strings.positionTime - }, - latitude: { - priority: 2, - name: Strings.positionLatitude - }, - longitude: { - priority: 3, - name: Strings.positionLongitude - }, - valid: { - priority: 4, - name: Strings.positionValid - }, - altitude: { - priority: 5, - name: Strings.positionAltitude - }, - speed: { - priority: 6, - name: Strings.positionSpeed - }, - course: { - priority: 7, - name: Strings.positionCourse - }, - address: { - priority: 8, - name: Strings.positionAddress - }, - protocol: { - priority: 9, - name: Strings.positionProtocol + updateLatest: function (store, data) { + var i; + if (!Ext.isArray(data)) { + data = [data]; + } + for (i = 0; i < data.length; i++) { + if (this.deviceId === data[i].get('deviceId')) { + this.updatePosition(data[i]); + } } }, formatValue: function (value) { if (typeof (id) === 'number') { - return value.toFixed(2); + return Number(value.toFixed(2)); } else { return value; } @@ -114,29 +105,22 @@ Ext.define('Traccar.view.StateController', { }, selectDevice: function (device) { - var found; + var position; this.deviceId = device.get('id'); - found = Ext.getStore('LatestPositions').query('deviceId', this.deviceId); - if (found.getCount() > 0) { - this.updatePosition(found.first()); + position = Ext.getStore('LatestPositions').findRecord('deviceId', this.deviceId, 0, false, false, true); + if (position) { + this.updatePosition(position); } else { Ext.getStore('Attributes').removeAll(); } }, selectReport: function (position) { - console.log(position); + this.deviceId = null; + this.updatePosition(position); }, - add: function (store, data) { - if (this.deviceId === data[0].get('deviceId')) { - this.updatePosition(data[0]); - } - }, - - update: function (store, data) { - if (this.deviceId === data.get('deviceId')) { - this.updatePosition(data); - } + clearReport: function (store) { + Ext.getStore('Attributes').removeAll(); } }); diff --git a/web/app/view/UserDevicesController.js b/web/app/view/UserDevicesController.js index a50ab8c80..aeb99c21c 100644 --- a/web/app/view/UserDevicesController.js +++ b/web/app/view/UserDevicesController.js @@ -52,11 +52,7 @@ Ext.define('Traccar.view.UserDevicesController', { userId: this.userId, deviceId: record.getData().id }, - callback: Traccar.app.getErrorHandler(this, function (options, success, response) { - if (!success) { - // TODO deselect again - } - }) + callback: Traccar.app.getErrorHandler() }); }, @@ -68,11 +64,7 @@ Ext.define('Traccar.view.UserDevicesController', { userId: this.userId, deviceId: record.getData().id }, - callback: Traccar.app.getErrorHandler(this, function (options, success, response) { - if (!success) { - // TODO select again - } - }) + callback: Traccar.app.getErrorHandler() }); } }); diff --git a/web/app/view/UsersController.js b/web/app/view/UsersController.js index 30eb8b1a5..3d0e813e8 100644 --- a/web/app/view/UsersController.js +++ b/web/app/view/UsersController.js @@ -55,8 +55,8 @@ Ext.define('Traccar.view.UsersController', { no: Strings.sharedCancel }, fn: function (btn) { + var store = Ext.getStore('Users'); if (btn === 'yes') { - var store = Ext.getStore('Users'); store.remove(user); store.sync(); } diff --git a/web/arrowstyle.js b/web/arrowstyle.js new file mode 100644 index 000000000..c1eb88909 --- /dev/null +++ b/web/arrowstyle.js @@ -0,0 +1,539 @@ +goog.provide('ol.style.Arrow'); + +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('ol'); +goog.require('ol.color'); +goog.require('ol.has'); +goog.require('ol.render.canvas'); +goog.require('ol.structs.IHasChecksum'); +goog.require('ol.style.AtlasManager'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Image'); +goog.require('ol.style.ImageState'); +goog.require('ol.style.Stroke'); + + + +/** + * @classdesc + * Set arrow style for vector features. + * + * @constructor + * @param {olx.style.ArrowOptions} options Options. + * @extends {ol.style.Image} + * @implements {ol.structs.IHasChecksum} + * @api + */ +ol.style.Arrow = function(options) { + + goog.asserts.assert(options.radius !== undefined, + 'must provide "radius"'); + + /** + * @private + * @type {Array.<string>} + */ + this.checksums_ = null; + + /** + * @private + * @type {HTMLCanvasElement} + */ + this.canvas_ = null; + + /** + * @private + * @type {HTMLCanvasElement} + */ + this.hitDetectionCanvas_ = null; + + /** + * @private + * @type {ol.style.Fill} + */ + this.fill_ = options.fill !== undefined ? options.fill : null; + + /** + * @private + * @type {Array.<number>} + */ + this.origin_ = [0, 0]; + + /** + * @private + * @type {number} + */ + this.radius_ = /** @type {number} */ (options.radius !== undefined ? + options.radius : options.radius1); + + /** + * @private + * @type {number} + */ + this.frontAngle_ = options.frontAngle !== undefined ? + options.frontAngle : Math.PI / 5; + + /** + * @private + * @type {number} + */ + this.backAngle_ = options.backAngle !== undefined ? + options.backAngle : 4 * Math.PI / 5; + + /** + * @private + * @type {ol.style.Stroke} + */ + this.stroke_ = options.stroke !== undefined ? options.stroke : null; + + /** + * @private + * @type {Array.<number>} + */ + this.anchor_ = null; + + /** + * @private + * @type {ol.Size} + */ + this.size_ = null; + + /** + * @private + * @type {ol.Size} + */ + this.imageSize_ = null; + + /** + * @private + * @type {ol.Size} + */ + this.hitDetectionImageSize_ = null; + + this.render_(options.atlasManager); + + /** + * @type {boolean} + */ + var snapToPixel = options.snapToPixel !== undefined ? + options.snapToPixel : true; + + goog.base(this, { + opacity: 1, + rotateWithView: false, + rotation: options.rotation !== undefined ? options.rotation : 0, + scale: 1, + snapToPixel: snapToPixel + }); + +}; +goog.inherits(ol.style.Arrow, ol.style.Image); + + +/** + * @inheritDoc + * @api + */ +ol.style.Arrow.prototype.getAnchor = function() { + return this.anchor_; +}; + + +/** + * Get front angle of the arrow. + * @return {number} Angle in radians. + * @api + */ +ol.style.Arrow.prototype.getFrontAngle = function() { + return this.frontAngle_; +}; + + +/** + * Get back angle of the arrow. + * @return {number} Angle in radians. + * @api + */ +ol.style.Arrow.prototype.getBackAngle = function() { + return this.backAngle_; +}; + + +/** + * Get the fill style for the arrow. + * @return {ol.style.Fill} Fill style. + * @api + */ +ol.style.Arrow.prototype.getFill = function() { + return this.fill_; +}; + + +/** + * @inheritDoc + */ +ol.style.Arrow.prototype.getHitDetectionImage = function(pixelRatio) { + return this.hitDetectionCanvas_; +}; + + +/** + * @inheritDoc + * @api + */ +ol.style.Arrow.prototype.getImage = function(pixelRatio) { + return this.canvas_; +}; + + +/** + * @inheritDoc + */ +ol.style.Arrow.prototype.getImageSize = function() { + return this.imageSize_; +}; + + +/** + * @inheritDoc + */ +ol.style.Arrow.prototype.getHitDetectionImageSize = function() { + return this.hitDetectionImageSize_; +}; + + +/** + * @inheritDoc + */ +ol.style.Arrow.prototype.getImageState = function() { + return ol.style.ImageState.LOADED; +}; + + +/** + * @inheritDoc + * @api + */ +ol.style.Arrow.prototype.getOrigin = function() { + return this.origin_; +}; + + +/** + * Get the (primary) radius for the arrow. + * @return {number} Radius. + * @api + */ +ol.style.Arrow.prototype.getRadius = function() { + return this.radius_; +}; + + +/** + * @inheritDoc + * @api + */ +ol.style.Arrow.prototype.getSize = function() { + return this.size_; +}; + + +/** + * Get the stroke style for the arrow. + * @return {ol.style.Stroke} Stroke style. + * @api + */ +ol.style.Arrow.prototype.getStroke = function() { + return this.stroke_; +}; + + +/** + * @inheritDoc + */ +ol.style.Arrow.prototype.listenImageChange = ol.nullFunction; + + +/** + * @inheritDoc + */ +ol.style.Arrow.prototype.load = ol.nullFunction; + + +/** + * @inheritDoc + */ +ol.style.Arrow.prototype.unlistenImageChange = ol.nullFunction; + + +/** + * @typedef {{ + * strokeStyle: (string|undefined), + * strokeWidth: number, + * size: number, + * lineCap: string, + * lineDash: Array.<number>, + * lineJoin: string, + * miterLimit: number + * }} + */ +ol.style.Arrow.RenderOptions; + + +/** + * @private + * @param {ol.style.AtlasManager|undefined} atlasManager + */ +ol.style.Arrow.prototype.render_ = function(atlasManager) { + var imageSize; + var lineCap = ''; + var lineJoin = ''; + var miterLimit = 0; + var lineDash = null; + var strokeStyle; + var strokeWidth = 0; + + if (this.stroke_) { + strokeStyle = ol.color.asString(this.stroke_.getColor()); + strokeWidth = this.stroke_.getWidth(); + if (strokeWidth === undefined) { + strokeWidth = ol.render.canvas.defaultLineWidth; + } + lineDash = this.stroke_.getLineDash(); + if (!ol.has.CANVAS_LINE_DASH) { + lineDash = null; + } + lineJoin = this.stroke_.getLineJoin(); + if (lineJoin === undefined) { + lineJoin = ol.render.canvas.defaultLineJoin; + } + lineCap = this.stroke_.getLineCap(); + if (lineCap === undefined) { + lineCap = ol.render.canvas.defaultLineCap; + } + miterLimit = this.stroke_.getMiterLimit(); + if (miterLimit === undefined) { + miterLimit = ol.render.canvas.defaultMiterLimit; + } + } + + var size = 2 * (this.radius_ + strokeWidth) + 1; + + /** @type {ol.style.Arrow.RenderOptions} */ + var renderOptions = { + strokeStyle: strokeStyle, + strokeWidth: strokeWidth, + size: size, + lineCap: lineCap, + lineDash: lineDash, + lineJoin: lineJoin, + miterLimit: miterLimit + }; + + if (atlasManager === undefined) { + // no atlas manager is used, create a new canvas + this.canvas_ = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement('CANVAS')); + + this.canvas_.height = size; + this.canvas_.width = size; + + // canvas.width and height are rounded to the closest integer + size = this.canvas_.width; + imageSize = size; + + var context = /** @type {CanvasRenderingContext2D} */ + (this.canvas_.getContext('2d')); + this.draw_(renderOptions, context, 0, 0); + + this.createHitDetectionCanvas_(renderOptions); + } else { + // an atlas manager is used, add the symbol to an atlas + size = Math.round(size); + + var hasCustomHitDetectionImage = !this.fill_; + var renderHitDetectionCallback; + if (hasCustomHitDetectionImage) { + // render the hit-detection image into a separate atlas image + renderHitDetectionCallback = + goog.bind(this.drawHitDetectionCanvas_, this, renderOptions); + } + + var id = this.getChecksum(); + var info = atlasManager.add( + id, size, size, goog.bind(this.draw_, this, renderOptions), + renderHitDetectionCallback); + goog.asserts.assert(info, 'arrow size is too large'); + + this.canvas_ = info.image; + this.origin_ = [info.offsetX, info.offsetY]; + imageSize = info.image.width; + + if (hasCustomHitDetectionImage) { + this.hitDetectionCanvas_ = info.hitImage; + this.hitDetectionImageSize_ = + [info.hitImage.width, info.hitImage.height]; + } else { + this.hitDetectionCanvas_ = this.canvas_; + this.hitDetectionImageSize_ = [imageSize, imageSize]; + } + } + + this.anchor_ = [size / 2, size / 2]; + this.size_ = [size, size]; + this.imageSize_ = [imageSize, imageSize]; +}; + + +/** + * @private + * @param {ol.style.Arrow.RenderOptions} renderOptions + * @param {CanvasRenderingContext2D} context + * @param {number} x The origin for the symbol (x). + * @param {number} y The origin for the symbol (y). + */ +ol.style.Arrow.prototype.draw_ = function(renderOptions, context, x, y) { + var innerRadius = this.radius_ / Math.sin(Math.PI - this.backAngle_ / 2) * + Math.sin(this.backAngle_ / 2 - this.frontAngle_); + + // reset transform + context.setTransform(1, 0, 0, 1, 0, 0); + + // then move to (x, y) + context.translate(x, y); + + + context.beginPath(); + + function lineTo(radius, angle) { + context.lineTo( + renderOptions.size / 2 + radius * Math.cos(angle + Math.PI / 2), + renderOptions.size / 2 - radius * Math.sin(angle + Math.PI / 2)); + } + + lineTo(this.radius_, 0); + lineTo(this.radius_, Math.PI - this.frontAngle_); + lineTo(innerRadius, Math.PI); + lineTo(this.radius_, this.frontAngle_ - Math.PI); + lineTo(this.radius_, 0); + + if (this.fill_) { + context.fillStyle = ol.color.asString(this.fill_.getColor()); + context.fill(); + } + if (this.stroke_) { + context.strokeStyle = renderOptions.strokeStyle; + context.lineWidth = renderOptions.strokeWidth; + if (renderOptions.lineDash) { + context.setLineDash(renderOptions.lineDash); + } + context.lineCap = renderOptions.lineCap; + context.lineJoin = renderOptions.lineJoin; + context.miterLimit = renderOptions.miterLimit; + context.stroke(); + } + context.closePath(); +}; + + +/** + * @private + * @param {ol.style.Arrow.RenderOptions} renderOptions + */ +ol.style.Arrow.prototype.createHitDetectionCanvas_ = + function(renderOptions) { + this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size]; + if (this.fill_) { + this.hitDetectionCanvas_ = this.canvas_; + return; + } + + // if no fill style is set, create an extra hit-detection image with a + // default fill style + this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement('CANVAS')); + var canvas = this.hitDetectionCanvas_; + + canvas.height = renderOptions.size; + canvas.width = renderOptions.size; + + var context = /** @type {CanvasRenderingContext2D} */ + (canvas.getContext('2d')); + this.drawHitDetectionCanvas_(renderOptions, context, 0, 0); +}; + + +/** + * @private + * @param {ol.style.Arrow.RenderOptions} renderOptions + * @param {CanvasRenderingContext2D} context + * @param {number} x The origin for the symbol (x). + * @param {number} y The origin for the symbol (y). + */ +ol.style.Arrow.prototype.drawHitDetectionCanvas_ = + function(renderOptions, context, x, y) { + var innerRadius = this.radius_ / Math.sin(Math.PI - this.backAngle_ / 2) * + Math.sin(this.backAngle_ / 2 - this.frontAngle_); + + // reset transform + context.setTransform(1, 0, 0, 1, 0, 0); + + // then move to (x, y) + context.translate(x, y); + + context.beginPath(); + + function lineTo(radius, angle) { + context.lineTo( + renderOptions.size / 2 + radius * Math.cos(angle + Math.PI / 2), + renderOptions.size / 2 - radius * Math.sin(angle + Math.PI / 2)); + } + + lineTo(this.radius_, 0); + lineTo(this.radius_, Math.PI - this.frontAngle_); + lineTo(innerRadius / 2, Math.PI); + lineTo(this.radius_, this.frontAngle_ - Math.PI); + lineTo(this.radius_, 0); + + context.fillStyle = ol.render.canvas.defaultFillStyle; + context.fill(); + if (this.stroke_) { + context.strokeStyle = renderOptions.strokeStyle; + context.lineWidth = renderOptions.strokeWidth; + if (renderOptions.lineDash) { + context.setLineDash(renderOptions.lineDash); + } + context.stroke(); + } + context.closePath(); +}; + + +/** + * @inheritDoc + */ +ol.style.Arrow.prototype.getChecksum = function() { + var strokeChecksum = this.stroke_ ? + this.stroke_.getChecksum() : '-'; + var fillChecksum = this.fill_ ? + this.fill_.getChecksum() : '-'; + + var recalculate = !this.checksums_ || + (strokeChecksum != this.checksums_[1] || + fillChecksum != this.checksums_[2] || + this.radius_ != this.checksums_[3] || + this.frontAngle_ != this.checksums_[4] || + this.backAngle_ != this.checksums_[5]); + + if (recalculate) { + var checksum = 'r' + strokeChecksum + fillChecksum + + (this.radius_ !== undefined ? this.radius_.toString() : '-') + + (this.frontAngle_ !== undefined ? this.frontAngle_.toString() : '-') + + (this.backAngle_ !== undefined ? this.backAngle_.toString() : '-'); + this.checksums_ = [checksum, strokeChecksum, fillChecksum, + this.radius_, this.frontAngle_, this.backAngle_]; + } + + return this.checksums_[0]; +}; diff --git a/web/debug.html b/web/debug.html index 201bdebd1..de63d32a2 100644 --- a/web/debug.html +++ b/web/debug.html @@ -5,12 +5,13 @@ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <title>Traccar</title> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/extjs/6.0.0/classic/theme-neptune/resources/theme-neptune-all.css"> -<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/ol3/3.10.1/ol.css"> +<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/ol3/3.11.1/ol.css"> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css"> <link rel="stylesheet" href="app.css"> <script src="//cdnjs.cloudflare.com/ajax/libs/extjs/6.0.0/ext-all-debug.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/extjs/6.0.0/classic/theme-neptune/theme-neptune.js"></script> -<script src="//cdnjs.cloudflare.com/ajax/libs/ol3/3.10.1/ol-debug.js"></script> +<script src="//cdnjs.cloudflare.com/ajax/libs/ol3/3.11.1/ol-debug.js"></script> +<script src="arrowstyle.js"></script> <script src="locale.js"></script> <script src="app.js"></script> </head> diff --git a/web/l10n/ar.json b/web/l10n/ar.json new file mode 100644 index 000000000..0d88e6a15 --- /dev/null +++ b/web/l10n/ar.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "جاري التحميل", + "sharedSave": "حفظ", + "sharedCancel": "إلغاء", + "sharedAdd": "إضافة", + "sharedEdit": "تعديل", + "sharedRemove": "حذف", + "sharedRemoveConfirm": "حذف العنصر", + "sharedKm": "كم", + "sharedMi": "ميل", + "sharedKmh": "كم/ساعه", + "sharedMph": "mph", + "sharedHour": "ساعه", + "sharedMinute": "دقيقة", + "sharedSecond": "ثانية", + "errorTitle": "خطأ", + "errorUnknown": "خطأ غير معروف", + "errorConnection": "خطأ في الاتصال", + "userName": "الاسم", + "userEmail": "بريد الكتروني", + "userPassword": "كلمة المرور", + "userAdmin": "مدير النظام", + "loginTitle": "دخول", + "loginLanguage": "اللغة", + "loginRegister": "تسجيل", + "loginLogin": "تسجيل دخول", + "loginFailed": "كلمة مرور او بريد خطأ", + "loginCreated": "تم تسجيل مستخدم جديد", + "loginLogout": "خروج", + "deviceDialog": "جهاز", + "deviceTitle": "أجهزة", + "deviceName": "الاسم ", + "deviceIdentifier": "المعرف", + "deviceCommand": "أمر ", + "settingsTitle": "إعدادات", + "settingsUser": "حساب", + "settingsServer": "خادم", + "settingsUsers": "مستخدم", + "settingsDistanceUnit": "مسافة", + "settingsSpeedUnit": "سرعة", + "reportTitle": "تقارير", + "reportDevice": "جهاز", + "reportFrom": "من", + "reportTo": "الي", + "reportShow": "اظهار", + "reportClear": "تفريغ الحقول", + "positionFixTime": "وقت", + "positionValid": "صحيح", + "positionLatitude": "خط العرض", + "positionLongitude": "خط الطول", + "positionAltitude": "ارتفاع عن سطح البحر", + "positionSpeed": "السرعة", + "positionCourse": "Course", + "positionAddress": "العنوان", + "positionProtocol": "بروتوكول", + "serverTitle": "اعدادت الخادم", + "serverZoom": "تقريب", + "serverRegistration": "تسجيل", + "mapTitle": "خريطة", + "mapLayer": "طبقة الخريطة", + "mapCustom": "خريطة محددة", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps Key", + "mapBingRoad": "Bing Maps Road", + "mapBingAerial": "Bing Maps Aerial", + "stateTitle": "حالة", + "stateName": "عنصر", + "stateValue": "قيمة", + "commandTitle": "أمر", + "commandSend": "ارسال", + "commandType": "النوع", + "commandSent": "تم ارسال الأمر", + "commandPositionPeriodic": "تقارير دورية", + "commandPositionStop": "ايقاف الارسال", + "commandEngineStop": "ايقاف المحرك", + "commandEngineResume": "تشغيل المحرك", + "commandFrequency": "معدل", + "commandUnit": "وحدة" +}
\ No newline at end of file diff --git a/web/l10n/bg.js b/web/l10n/bg.js deleted file mode 100644 index 8202ae35a..000000000 --- a/web/l10n/bg.js +++ /dev/null @@ -1,88 +0,0 @@ -var Strings = { - sharedLoading: 'Зареждане...', - sharedSave: 'Запази', - sharedCancel: 'Отказ', - sharedAdd: 'Добави', - sharedEdit: 'Редактирай', - sharedRemove: 'Премахни', - sharedRemoveConfirm: 'Премахване на Устройство?', - sharedKm: 'км', - sharedMi: 'мл', - sharedKmh: 'км/ч', - sharedMph: 'мл/ч', - sharedHour: 'Час', - sharedMinute: 'Минута', - sharedSecond: 'Секунда', - - errorTitle: 'Грешка', - errorUnknown: 'Непозната Грешка', - - userName: 'Име', - userEmail: 'Пощенска кутия', - userPassword: 'Парола', - userAdmin: 'Admin', - - loginTitle: 'Идентификация', - loginLanguage: 'Език', - loginRegister: 'Регистрация', - loginLogin: 'Вход', - loginFailed: 'Грешен потребител или парола', - loginCreated: 'Регистриран Нов Потребител', - loginLogout: 'Изход', - - deviceDialog: 'Обекти', - deviceTitle: 'Устройства', - deviceName: 'Име', - deviceIdentifier: 'Идентификатор', - deviceCommand: 'Команда', - - settingsTitle: 'Настройки', - settingsUser: 'Профил', - settingsServer: 'Сървър', - settingsUsers: 'Потребител', - settingsDistanceUnit: 'Разстояние', - settingsSpeedUnit: 'Скорост', - - reportTitle: 'Доклад', - reportDevice: 'Устройство', - reportFrom: 'От', - reportTo: 'До', - reportShow: 'Покажи', - reportClear: 'Изчисти', - - positionTime: 'Време', - positionValid: 'Валидност', - positionLatitude: 'Географска Ширина', - positionLongitude: 'Географска Дължина', - positionAltitude: 'Надморска височина', - positionSpeed: 'Скорост', - positionCourse: 'Посока', - positionAddress: 'Адрес', - positionProtocol: 'Протокол', - - serverTitle: 'Настройки на Сървъра', - serverZoom: 'Приближение', - serverRegistration: 'Регистрация', - - mapTitle: 'Карта', - mapLayer: 'Слой', - mapCustom: 'Потребителска Карта', - mapOsm: 'Open Street Map', - mapBingKey: 'Bing Maps Key', - mapBingRoad: 'Bing Maps Road', - mapBingAerial: 'Bing Maps Aerial', - - stateTitle: 'Състояние', - stateName: 'Параметър', - stateValue: 'Стойност', - - commandTitle: 'Команда', - commandSend: 'Изпрати', - commandType: 'Тип', - commandPositionPeriodic: 'Периодичен Доклад', - commandPositionStop: 'Спри Доклада', - commandEngineStop: 'Спри Двигател', - commandEngineResume: 'Стартирай Двигател', - commandFrequency: 'Честота', - commandUnit: 'Обект' -}; diff --git a/web/l10n/bg.json b/web/l10n/bg.json new file mode 100644 index 000000000..80f861651 --- /dev/null +++ b/web/l10n/bg.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Зареждане...", + "sharedSave": "Запази", + "sharedCancel": "Отказ", + "sharedAdd": "Добави", + "sharedEdit": "Редактирай", + "sharedRemove": "Премахни", + "sharedRemoveConfirm": "Премахване на Устройство?", + "sharedKm": "км", + "sharedMi": "мл", + "sharedKmh": "км/ч", + "sharedMph": "мл/ч", + "sharedHour": "Час", + "sharedMinute": "Минута", + "sharedSecond": "Секунда", + "errorTitle": "Грешка", + "errorUnknown": "Непозната Грешка", + "errorConnection": "Грешка във връзката", + "userName": "Име", + "userEmail": "Пощенска кутия", + "userPassword": "Парола", + "userAdmin": "Admin", + "loginTitle": "Идентификация", + "loginLanguage": "Език", + "loginRegister": "Регистрация", + "loginLogin": "Вход", + "loginFailed": "Грешен потребител или парола", + "loginCreated": "Регистриран Нов Потребител", + "loginLogout": "Изход", + "deviceDialog": "Обекти", + "deviceTitle": "Устройства", + "deviceName": "Име", + "deviceIdentifier": "Идентификатор", + "deviceCommand": "Команда", + "settingsTitle": "Настройки", + "settingsUser": "Профил", + "settingsServer": "Сървър", + "settingsUsers": "Потребител", + "settingsDistanceUnit": "Разстояние", + "settingsSpeedUnit": "Скорост", + "reportTitle": "Доклад", + "reportDevice": "Устройство", + "reportFrom": "От", + "reportTo": "До", + "reportShow": "Покажи", + "reportClear": "Изчисти", + "positionFixTime": "Време", + "positionValid": "Валидност", + "positionLatitude": "Географска Ширина", + "positionLongitude": "Географска Дължина", + "positionAltitude": "Надморска височина", + "positionSpeed": "Скорост", + "positionCourse": "Посока", + "positionAddress": "Адрес", + "positionProtocol": "Протокол", + "serverTitle": "Настройки на Сървъра", + "serverZoom": "Приближение", + "serverRegistration": "Регистрация", + "mapTitle": "Карта", + "mapLayer": "Слой", + "mapCustom": "Потребителска Карта", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps Key", + "mapBingRoad": "Bing Maps Road", + "mapBingAerial": "Bing Maps Aerial", + "stateTitle": "Състояние", + "stateName": "Параметър", + "stateValue": "Стойност", + "commandTitle": "Команда", + "commandSend": "Изпрати", + "commandType": "Тип", + "commandSent": "Съобщението е изпратено", + "commandPositionPeriodic": "Периодичен Доклад", + "commandPositionStop": "Спри Доклада", + "commandEngineStop": "Спри Двигател", + "commandEngineResume": "Стартирай Двигател", + "commandFrequency": "Честота", + "commandUnit": "Обект" +}
\ No newline at end of file diff --git a/web/l10n/cs.js b/web/l10n/cs.js deleted file mode 100755 index 5d6c927e4..000000000 --- a/web/l10n/cs.js +++ /dev/null @@ -1,89 +0,0 @@ -var Strings = { - sharedLoading: 'Načítání...', - sharedSave: 'Uložit', - sharedCancel: 'Zrušit', - sharedAdd: 'Přidat', - sharedEdit: 'Změnit', - sharedRemove: 'Odstranit', - sharedRemoveConfirm: 'Odstranit položku?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'Hodina', - sharedMinute: 'Minuta', - sharedSecond: 'Sekunda', - - errorTitle: 'Chyba', - errorUnknown: 'Neznámá chyba', - - userName: 'Jméno', - userEmail: 'Email', - userPassword: 'Heslo', - userAdmin: 'Admin', - - loginTitle: 'Přihlášení', - loginLanguage: 'Jazyk', - loginRegister: 'Registrace', - loginLogin: 'Přihlášení', - loginFailed: 'Nesprávný email nebo heslo', - loginCreated: 'Nový uživatel byl zaregistrován', - loginLogout: 'Odhlášení', - - deviceDialog: 'Zařízení', - deviceTitle: 'Zařízení', - deviceName: 'Název', - deviceIdentifier: 'Identifikace', - deviceCommand: 'Příkaz', - - settingsTitle: 'Nastavení', - settingsUser: 'Účet', - settingsServer: 'Server', - settingsUsers: 'Uživatelé', - settingsDistanceUnit: 'Vzdálenost', - settingsSpeedUnit: 'Rychlost', - - reportTitle: 'Zpráva', - reportDevice: 'Zařízení', - reportFrom: 'Od', - reportTo: 'Komu', - reportShow: 'Zobrazit', - reportClear: 'Vyčistit', - - positionTime: 'Čas', - positionValid: 'Správný', - positionLatitude: 'Šířka', - positionLongitude: 'Délka', - positionAltitude: 'Výška', - positionSpeed: 'Rychlost', - positionCourse: 'Směr', - positionAddress: 'Adresa', - positionProtocol: 'Protokol', - - serverTitle: 'Nastavení serveru', - serverZoom: 'Přiblížení', - serverRegistration: 'Registrace', - - mapTitle: 'Mapa', - mapLayer: 'Vrstva mapy', - mapCustom: 'Upravená mapa', - mapOsm: 'Open Street mapa', - mapBingKey: 'Bing Maps klíč', - mapBingRoad: 'Bing Maps cesta', - mapBingAerial: 'Bing Maps anténa', - - stateTitle: 'Stav', - stateName: 'Atribut', - stateValue: 'Hodnota', - - commandTitle: 'Příkaz', - commandSend: 'Odeslat', - commandType: 'Napsat', - commandSent: 'Příkaz byl odeslán', - commandPositionPeriodic: 'Pravidelný report', - commandPositionStop: 'Zastavit report', - commandEngineStop: 'Zastavit motor', - commandEngineResume: 'Nastartovat motor', - commandFrequency: 'Frekvence', - commandUnit: 'Jednotka' -}; diff --git a/web/l10n/cs.json b/web/l10n/cs.json new file mode 100644 index 000000000..1518ffbc3 --- /dev/null +++ b/web/l10n/cs.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Načítání...", + "sharedSave": "Uložit", + "sharedCancel": "Zrušit", + "sharedAdd": "Přidat", + "sharedEdit": "Změnit", + "sharedRemove": "Odstranit", + "sharedRemoveConfirm": "Odstranit položku?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "Hodina", + "sharedMinute": "Minuta", + "sharedSecond": "Sekunda", + "errorTitle": "Chyba", + "errorUnknown": "Neznámá chyba", + "errorConnection": "Chyba spojení", + "userName": "Jméno", + "userEmail": "Email", + "userPassword": "Heslo", + "userAdmin": "Admin", + "loginTitle": "Přihlášení", + "loginLanguage": "Jazyk", + "loginRegister": "Registrace", + "loginLogin": "Přihlášení", + "loginFailed": "Nesprávný email nebo heslo", + "loginCreated": "Nový uživatel byl zaregistrován", + "loginLogout": "Odhlášení", + "deviceDialog": "Zařízení", + "deviceTitle": "Zařízení", + "deviceName": "Název", + "deviceIdentifier": "Identifikace", + "deviceCommand": "Příkaz", + "settingsTitle": "Nastavení", + "settingsUser": "Účet", + "settingsServer": "Server", + "settingsUsers": "Uživatelé", + "settingsDistanceUnit": "Vzdálenost", + "settingsSpeedUnit": "Rychlost", + "reportTitle": "Zpráva", + "reportDevice": "Zařízení", + "reportFrom": "Od", + "reportTo": "Komu", + "reportShow": "Zobrazit", + "reportClear": "Vyčistit", + "positionFixTime": "Čas", + "positionValid": "Správný", + "positionLatitude": "Šířka", + "positionLongitude": "Délka", + "positionAltitude": "Výška", + "positionSpeed": "Rychlost", + "positionCourse": "Směr", + "positionAddress": "Adresa", + "positionProtocol": "Protokol", + "serverTitle": "Nastavení serveru", + "serverZoom": "Přiblížení", + "serverRegistration": "Registrace", + "mapTitle": "Mapa", + "mapLayer": "Vrstva mapy", + "mapCustom": "Upravená mapa", + "mapOsm": "Open Street mapa", + "mapBingKey": "Bing Maps klíč", + "mapBingRoad": "Bing Maps cesta", + "mapBingAerial": "Bing Maps anténa", + "stateTitle": "Stav", + "stateName": "Atribut", + "stateValue": "Hodnota", + "commandTitle": "Příkaz", + "commandSend": "Odeslat", + "commandType": "Napsat", + "commandSent": "Příkaz byl odeslán", + "commandPositionPeriodic": "Pravidelný report", + "commandPositionStop": "Zastavit report", + "commandEngineStop": "Zastavit motor", + "commandEngineResume": "Nastartovat motor", + "commandFrequency": "Frekvence", + "commandUnit": "Jednotka" +}
\ No newline at end of file diff --git a/web/l10n/da.json b/web/l10n/da.json new file mode 100644 index 000000000..1a99b74f2 --- /dev/null +++ b/web/l10n/da.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Loading...", + "sharedSave": "Gem", + "sharedCancel": "Fortryd", + "sharedAdd": "Tilføj", + "sharedEdit": "Rediger", + "sharedRemove": "Fjern", + "sharedRemoveConfirm": "Fjern enhed?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/t", + "sharedMph": "mph", + "sharedHour": "Time", + "sharedMinute": "Minut", + "sharedSecond": "Sekund", + "errorTitle": "Fejl", + "errorUnknown": "Ukendt Fejl", + "errorConnection": "Tilslutning fejl", + "userName": "Navn", + "userEmail": "Email", + "userPassword": "Kodeord", + "userAdmin": "Admin", + "loginTitle": "Log på", + "loginLanguage": "Sprog", + "loginRegister": "Registrer", + "loginLogin": "Log på", + "loginFailed": "Fejl i email adresse eller kodeord", + "loginCreated": "Ny bruger er registreret", + "loginLogout": "Log af", + "deviceDialog": "Enhed", + "deviceTitle": "Enheder", + "deviceName": "Navn", + "deviceIdentifier": "Imei nr", + "deviceCommand": "Kommando", + "settingsTitle": "Indstillinger", + "settingsUser": "Konto", + "settingsServer": "Server", + "settingsUsers": "Brugere", + "settingsDistanceUnit": "Distance", + "settingsSpeedUnit": "Hastighed", + "reportTitle": "Rapporter", + "reportDevice": "Enhed", + "reportFrom": "Fra", + "reportTo": "Til", + "reportShow": "Vis", + "reportClear": "Ryd", + "positionFixTime": "Tid", + "positionValid": "Valid", + "positionLatitude": ">Breddegrad", + "positionLongitude": "Længdegrad", + "positionAltitude": "Højde", + "positionSpeed": "Hastighed", + "positionCourse": "Kurs", + "positionAddress": "Addresse", + "positionProtocol": "Protocol", + "serverTitle": "Server indstillinger", + "serverZoom": "Zoom", + "serverRegistration": "Registrering", + "mapTitle": "Kort", + "mapLayer": "Kort opsætning", + "mapCustom": "Brugerdefineret Kort", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps Key", + "mapBingRoad": "Bing Maps Road", + "mapBingAerial": "Bing Maps Aerial", + "stateTitle": "Status", + "stateName": "Parameter", + "stateValue": "Værdi", + "commandTitle": "Kommando", + "commandSend": "Send", + "commandType": "Type", + "commandSent": "Kommando er blevet sendt", + "commandPositionPeriodic": "Periodisk Rapportering", + "commandPositionStop": "Stop Rapportering", + "commandEngineStop": "Stop motor", + "commandEngineResume": "Genstart motor", + "commandFrequency": "Frekvens", + "commandUnit": "Enhed" +}
\ No newline at end of file diff --git a/web/l10n/de.js b/web/l10n/de.js deleted file mode 100644 index 0ababab34..000000000 --- a/web/l10n/de.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: 'Lade...', - sharedSave: 'Speichern', - sharedCancel: 'Abbrechen', - sharedAdd: 'Hinzufügen', - sharedEdit: 'Bearbeiten', - sharedRemove: 'Entfernen', - sharedRemoveConfirm: 'Objekt entfernen?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'Stunde', - sharedMinute: 'Minute', - sharedSecond: 'Sekunde', - - errorTitle: 'Fehler', - errorUnknown: 'Unbekannter Fehler', - - userName: 'Name', - userEmail: 'Email', - userPassword: 'Passwort', - userAdmin: 'Admin', - - loginTitle: 'Anmeldung', - loginLanguage: 'Sprache', - loginRegister: 'Registrieren', - loginLogin: 'Anmelden', - loginFailed: 'Falsche Emailadresse oder Passwort', - loginCreated: 'Neuer Benutzer wurde registriert', - loginLogout: 'Abmelden', - - deviceDialog: 'Gerät', - deviceTitle: 'Geräte', - deviceName: 'Name', - deviceIdentifier: 'Kennung', - deviceCommand: 'Befehl', - - settingsTitle: 'Einstellungen', - settingsUser: 'Benutzerkonto', - settingsServer: 'Server', - settingsUsers: 'Benutzer', - settingsDistanceUnit: 'Entfernung', - settingsSpeedUnit: 'Geschwindigkeit', - - reportTitle: 'Berichte', - reportDevice: 'Gerät', - reportFrom: 'Von', - reportTo: 'Bis', - reportShow: 'Anzeigen', - reportClear: 'Leeren', - - positionTime: 'Zeit', - positionValid: 'Gültig', - positionLatitude: 'Latitude', - positionLongitude: 'Longitude', - positionAltitude: 'Altitude', - positionSpeed: 'Geschwindigkeit', - positionCourse: 'Richtung', - positionAddress: 'Adresse', - positionProtocol: 'Protokoll', - - serverTitle: 'Server Einstellungen', - serverZoom: 'Zoomen', - serverRegistration: 'Registrierung zulassen', - - mapTitle: 'Karte', - mapLayer: 'Karten Layer', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Strassenkarte', - mapBingAerial: 'Bing Luftbilder', - - stateTitle: 'Status', - stateName: 'Parameter', - stateValue: 'Wert', - - commandTitle: 'Befehl', - commandSend: 'Senden', - commandType: 'Typ', - commandPositionPeriodic: 'Position Fix', - commandPositionStop: 'Position Stop', - commandEngineStop: 'Motor Stop', - commandEngineResume: 'Motor fortsetzen', - commandFrequency: 'Frequenz', - commandUnit: 'Einheit' -}; diff --git a/web/l10n/de.json b/web/l10n/de.json new file mode 100644 index 000000000..e47152ddc --- /dev/null +++ b/web/l10n/de.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Lade...", + "sharedSave": "Speichern", + "sharedCancel": "Abbrechen", + "sharedAdd": "Hinzufügen", + "sharedEdit": "Bearbeiten", + "sharedRemove": "Entfernen", + "sharedRemoveConfirm": "Objekt entfernen?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "Stunde", + "sharedMinute": "Minute", + "sharedSecond": "Sekunde", + "errorTitle": "Fehler", + "errorUnknown": "Unbekannter Fehler", + "errorConnection": "Verbindungsfehler", + "userName": "Name", + "userEmail": "Email", + "userPassword": "Passwort", + "userAdmin": "Admin", + "loginTitle": "Anmeldung", + "loginLanguage": "Sprache", + "loginRegister": "Registrieren", + "loginLogin": "Anmelden", + "loginFailed": "Falsche Emailadresse oder Passwort", + "loginCreated": "Neuer Benutzer wurde registriert", + "loginLogout": "Abmelden", + "deviceDialog": "Gerät", + "deviceTitle": "Geräte", + "deviceName": "Name", + "deviceIdentifier": "Kennung", + "deviceCommand": "Befehl", + "settingsTitle": "Einstellungen", + "settingsUser": "Benutzerkonto", + "settingsServer": "Server", + "settingsUsers": "Benutzer", + "settingsDistanceUnit": "Entfernung", + "settingsSpeedUnit": "Geschwindigkeit", + "reportTitle": "Berichte", + "reportDevice": "Gerät", + "reportFrom": "Von", + "reportTo": "Bis", + "reportShow": "Anzeigen", + "reportClear": "Leeren", + "positionFixTime": "Zeit", + "positionValid": "Gültig", + "positionLatitude": "Latitude", + "positionLongitude": "Longitude", + "positionAltitude": "Altitude", + "positionSpeed": "Geschwindigkeit", + "positionCourse": "Richtung", + "positionAddress": "Adresse", + "positionProtocol": "Protokoll", + "serverTitle": "Server Einstellungen", + "serverZoom": "Zoomen", + "serverRegistration": "Registrierung zulassen", + "mapTitle": "Karte", + "mapLayer": "Karten Layer", + "mapCustom": "Benutzerspezifische Karte", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps Key", + "mapBingRoad": "Bing Strassenkarte", + "mapBingAerial": "Bing Luftbilder", + "stateTitle": "Status", + "stateName": "Parameter", + "stateValue": "Wert", + "commandTitle": "Befehl", + "commandSend": "Senden", + "commandType": "Typ", + "commandSent": "Befehl wurde gesendet", + "commandPositionPeriodic": "Position Fix", + "commandPositionStop": "Position Stop", + "commandEngineStop": "Motor Stop", + "commandEngineResume": "Motor fortsetzen", + "commandFrequency": "Frequenz", + "commandUnit": "Einheit" +}
\ No newline at end of file diff --git a/web/l10n/dk.js b/web/l10n/dk.js deleted file mode 100644 index 831e5686f..000000000 --- a/web/l10n/dk.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: 'Loading...', - sharedSave: 'Gem', - sharedCancel: 'Fortryd', - sharedAdd: 'Tilføj', - sharedEdit: 'Rediger', - sharedRemove: 'Fjern', - sharedRemoveConfirm: 'Fjern enhed?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/t', - sharedMph: 'mph', - sharedHour: 'Time', - sharedMinute: 'Minut', - sharedSecond: 'Sekund', - - errorTitle: 'Fejl', - errorUnknown: 'Ukendt Fejl', - - userName: 'Navn', - userEmail: 'Email', - userPassword: 'Kodeord', - userAdmin: 'Admin', - - loginTitle: 'Log på', - loginLanguage: 'Sprog', - loginRegister: 'Registrer', - loginLogin: 'Log på', - loginFailed: 'Fejl i email adresse eller kodeord', - loginCreated: 'Ny bruger er registreret', - loginLogout: 'Log af', - - deviceDialog: 'Enhed', - deviceTitle: 'Enheder', - deviceName: 'Navn', - deviceIdentifier: 'Imei nr', - deviceCommand: 'Kommando', - - settingsTitle: 'Indstillinger', - settingsUser: 'Konto', - settingsServer: 'Server', - settingsUsers: 'Brugere', - settingsDistanceUnit: 'Distance', - settingsSpeedUnit: 'Hastighed', - - reportTitle: 'Rapporter', - reportDevice: 'Enhed', - reportFrom: 'Fra', - reportTo: 'Til', - reportShow: 'Vis', - reportClear: 'Ryd', - - positionTime: 'Tid', - positionValid: 'Valid', - positionLatitude: '>Breddegrad', - positionLongitude: 'Længdegrad', - positionAltitude: 'Højde', - positionSpeed: 'Hastighed', - positionCourse: 'Kurs', - positionAddress: 'Addresse', - positionProtocol: 'Protocol', - - serverTitle: 'Server indstillinger', - serverZoom: 'Zoom', - serverRegistration: 'Registrering', - - mapTitle: 'Kort', - mapLayer: 'Kort opsætning', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Maps Road', - mapBingAerial: 'Bing Maps Aerial', - - stateTitle: 'Status', - stateName: 'Parameter', - stateValue: 'Værdi', - - commandTitle: 'Kommando', - commandSend: 'Send', - commandType: 'Type', - commandPositionPeriodic: 'Periodisk Rapportering', - commandPositionStop: 'Stop Rapportering', - commandEngineStop: 'Stop motor', - commandEngineResume: 'Genstart motor', - commandFrequency: 'Frekvens', - commandUnit: 'Enhed' -}; diff --git a/web/l10n/el.js b/web/l10n/el.js deleted file mode 100755 index d2d6495b7..000000000 --- a/web/l10n/el.js +++ /dev/null @@ -1,86 +0,0 @@ -var strings = { - sharedLoading: 'Φόρτωση...', - sharedSave: 'Αποθήκευση', - sharedCancel: 'Άκυρον', - sharedAdd: 'Προσθήκη', - sharedEdit: 'Επεξεργασία', - sharedRemove: 'Διαγραφή', - sharedRemoveConfirm: 'Διαγραφη στοιχείου;', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'Ώρα', - sharedMinute: 'Λεπτά', - sharedSecond: 'Δευτερόλεπτα', - - errorTitle: 'Σφάλμα', - errorUnknown: 'Άνωστο σφάλμα', - - userName: 'Όνομα', - userEmail: 'Email', - userPassword: 'Συνθηματικό', - userAdmin: 'Admin', - - loginTitle: 'Σύνδεση', - loginLanguage: 'Γλώσσα', - loginRegister: 'Εγγραφή', - loginLogin: 'Σύνδεση', - loginFailed: 'Εσφαλμένη διεύθυνση ή εσφαλμένο συνθηματικό', - loginCreated: 'Ο νέος χρήστης καταχωρήθηκε.', - loginLogout: 'Αποσύνδεση', - - deviceDialog: 'Συσκευή', - deviceTitle: 'Συσκευές', - deviceName: 'Όνομα', - deviceIdentifier: 'Αναγνωριστικό', - deviceCommand: 'Εντολή', - - settingsTitle: 'Ρυθμίσεις', - settingsUser: 'Λογαριασμός', - settingsServer: 'Εξυπηρετητής', - settingsUsers: 'Χρήστες', - settingsDistanceUnit: 'Απόσταση', - settingsSpeedUnit: 'Ταχύτητα', - - reportTitle: 'Αναφορές', - reportDevice: 'Συσκευή', - reportFrom: 'Από', - reportTo: 'Έως', - reportShow: 'Προβολή', - reportClear: 'Καθαρισμός', - - positionTime: 'Χρόνος', - positionValid: 'Έγκυρο', - positionLatitude: 'Γ. πλάτος', - positionLongitude: 'Γ. μήκος', - positionAltitude: 'Υψόμετρο', - positionSpeed: 'Ταχύτητα', - positionCourse: 'Πορεία', - positionAddress: 'Διεύθυνση', - positionProtocol: 'Πρωτόκολλο', - - serverTitle: 'Ρυθμίσεις εξυπηρετητή', - serverZoom: 'Εστίαση', - serverRegistration: 'Εγγραφή', - - mapTitle: 'Χάρτης', - mapLayer: 'Επιλογή χάρτη', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Maps Road', - mapBingAerial: 'Bing Maps Aerial', - - stateTitle: 'Κατάσταση', - stateName: 'Παράμετρος', - stateValue: 'Τιμή', - - commandTitle: 'Εντολή', - commandSend: 'Αποστολή', - commandType: 'Τύπος', - commandPositionPeriodic: 'Περιοδικές αναφορές', - commandPositionStop: 'Λήξη αναφορών', - commandEngineStop: 'Κλείσιμο', - commandEngineResume: 'Επανεκκίνηση', - commandFrequency: 'Συχνότητα', - commandUnit: 'Μονάδα' -}; diff --git a/web/l10n/el.json b/web/l10n/el.json new file mode 100644 index 000000000..36c51a001 --- /dev/null +++ b/web/l10n/el.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Φόρτωση...", + "sharedSave": "Αποθήκευση", + "sharedCancel": "Άκυρον", + "sharedAdd": "Προσθήκη", + "sharedEdit": "Επεξεργασία", + "sharedRemove": "Διαγραφή", + "sharedRemoveConfirm": "Διαγραφη στοιχείου;", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "Ώρα", + "sharedMinute": "Λεπτά", + "sharedSecond": "Δευτερόλεπτα", + "errorTitle": "Σφάλμα", + "errorUnknown": "Άγνωστο σφάλμα", + "errorConnection": "Σφάλμα σύνδεσης", + "userName": "Όνομα", + "userEmail": "Ηλ. διεύθυνση", + "userPassword": "Συνθηματικό", + "userAdmin": "Admin", + "loginTitle": "Σύνδεση", + "loginLanguage": "Γλώσσα", + "loginRegister": "Εγγραφή", + "loginLogin": "Σύνδεση", + "loginFailed": "Εσφαλμένη διεύθυνση ή εσφαλμένο συνθηματικό", + "loginCreated": "Ο νέος χρήστης καταχωρήθηκε.", + "loginLogout": "Αποσύνδεση", + "deviceDialog": "Συσκευή", + "deviceTitle": "Συσκευές", + "deviceName": "Όνομα", + "deviceIdentifier": "Αναγνωριστικό", + "deviceCommand": "Εντολή", + "settingsTitle": "Ρυθμίσεις", + "settingsUser": "Λογαριασμός", + "settingsServer": "Εξυπηρετητής", + "settingsUsers": "Χρήστες", + "settingsDistanceUnit": "Απόσταση", + "settingsSpeedUnit": "Ταχύτητα", + "reportTitle": "Αναφορές", + "reportDevice": "Συσκευή", + "reportFrom": "Από", + "reportTo": "Έως", + "reportShow": "Προβολή", + "reportClear": "Καθαρισμός", + "positionFixTime": "Χρόνος", + "positionValid": "Έγκυρο", + "positionLatitude": "Γ. πλάτος", + "positionLongitude": "Γ. μήκος", + "positionAltitude": "Υψόμετρο", + "positionSpeed": "Ταχύτητα", + "positionCourse": "Πορεία", + "positionAddress": "Διεύθυνση", + "positionProtocol": "Πρωτόκολλο", + "serverTitle": "Ρυθμίσεις εξυπηρετητή", + "serverZoom": "Εστίαση", + "serverRegistration": "Εγγραφή", + "mapTitle": "Χάρτης", + "mapLayer": "Επιλογή χάρτη", + "mapCustom": "Προσαρμοσμένος χάρτης", + "mapOsm": "Open Street Map", + "mapBingKey": "Κλειδί Bing Maps", + "mapBingRoad": "Bing Maps Road", + "mapBingAerial": "Bing Maps Aerial", + "stateTitle": "Κατάσταση", + "stateName": "Παράμετρος", + "stateValue": "Τιμή", + "commandTitle": "Εντολή", + "commandSend": "Αποστολή", + "commandType": "Τύπος", + "commandSent": "Η εντολή έχει σταλεί.", + "commandPositionPeriodic": "Περιοδικές αναφορές", + "commandPositionStop": "Λήξη αναφορών", + "commandEngineStop": "Κλείσιμο", + "commandEngineResume": "Επανεκκίνηση", + "commandFrequency": "Συχνότητα", + "commandUnit": "Μονάδα" +}
\ No newline at end of file diff --git a/web/l10n/en.js b/web/l10n/en.js deleted file mode 100644 index cd6bf3038..000000000 --- a/web/l10n/en.js +++ /dev/null @@ -1,89 +0,0 @@ -var Strings = { - sharedLoading: 'Loading...', - sharedSave: 'Save', - sharedCancel: 'Cancel', - sharedAdd: 'Add', - sharedEdit: 'Edit', - sharedRemove: 'Remove', - sharedRemoveConfirm: 'Remove item?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'Hour', - sharedMinute: 'Minute', - sharedSecond: 'Second', - - errorTitle: 'Error', - errorUnknown: 'Unknown error', - - userName: 'Name', - userEmail: 'Email', - userPassword: 'Password', - userAdmin: 'Admin', - - loginTitle: 'Login', - loginLanguage: 'Language', - loginRegister: 'Register', - loginLogin: 'Login', - loginFailed: 'Incorrect email address or password', - loginCreated: 'New user has been registered', - loginLogout: 'Logout', - - deviceDialog: 'Device', - deviceTitle: 'Devices', - deviceName: 'Name', - deviceIdentifier: 'Identifier', - deviceCommand: 'Command', - - settingsTitle: 'Settings', - settingsUser: 'Account', - settingsServer: 'Server', - settingsUsers: 'Users', - settingsDistanceUnit: 'Distance', - settingsSpeedUnit: 'Speed', - - reportTitle: 'Reports', - reportDevice: 'Device', - reportFrom: 'From', - reportTo: 'To', - reportShow: 'Show', - reportClear: 'Clear', - - positionTime: 'Time', - positionValid: 'Valid', - positionLatitude: 'Latitude', - positionLongitude: 'Longitude', - positionAltitude: 'Altitude', - positionSpeed: 'Speed', - positionCourse: 'Course', - positionAddress: 'Address', - positionProtocol: 'Protocol', - - serverTitle: 'Server Settings', - serverZoom: 'Zoom', - serverRegistration: 'Registration', - - mapTitle: 'Map', - mapLayer: 'Map Layer', - mapCustom: 'Custom Map', - mapOsm: 'Open Street Map', - mapBingKey: 'Bing Maps Key', - mapBingRoad: 'Bing Maps Road', - mapBingAerial: 'Bing Maps Aerial', - - stateTitle: 'State', - stateName: 'Attribute', - stateValue: 'Value', - - commandTitle: 'Command', - commandSend: 'Send', - commandType: 'Type', - commandSent: 'Command has been sent', - commandPositionPeriodic: 'Periodic Reporting', - commandPositionStop: 'Stop Reporting', - commandEngineStop: 'Engine Stop', - commandEngineResume: 'Engine Resume', - commandFrequency: 'Frequency', - commandUnit: 'Unit' -}; diff --git a/web/l10n/en.json b/web/l10n/en.json new file mode 100644 index 000000000..a3489fbe1 --- /dev/null +++ b/web/l10n/en.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Loading...", + "sharedSave": "Save", + "sharedCancel": "Cancel", + "sharedAdd": "Add", + "sharedEdit": "Edit", + "sharedRemove": "Remove", + "sharedRemoveConfirm": "Remove item?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "Hour", + "sharedMinute": "Minute", + "sharedSecond": "Second", + "errorTitle": "Error", + "errorUnknown": "Unknown error", + "errorConnection": "Connection error", + "userName": "Name", + "userEmail": "Email", + "userPassword": "Password", + "userAdmin": "Admin", + "loginTitle": "Login", + "loginLanguage": "Language", + "loginRegister": "Register", + "loginLogin": "Login", + "loginFailed": "Incorrect email address or password", + "loginCreated": "New user has been registered", + "loginLogout": "Logout", + "deviceDialog": "Device", + "deviceTitle": "Devices", + "deviceName": "Name", + "deviceIdentifier": "Identifier", + "deviceCommand": "Command", + "settingsTitle": "Settings", + "settingsUser": "Account", + "settingsServer": "Server", + "settingsUsers": "Users", + "settingsDistanceUnit": "Distance", + "settingsSpeedUnit": "Speed", + "reportTitle": "Reports", + "reportDevice": "Device", + "reportFrom": "From", + "reportTo": "To", + "reportShow": "Show", + "reportClear": "Clear", + "positionFixTime": "Time", + "positionValid": "Valid", + "positionLatitude": "Latitude", + "positionLongitude": "Longitude", + "positionAltitude": "Altitude", + "positionSpeed": "Speed", + "positionCourse": "Course", + "positionAddress": "Address", + "positionProtocol": "Protocol", + "serverTitle": "Server Settings", + "serverZoom": "Zoom", + "serverRegistration": "Registration", + "mapTitle": "Map", + "mapLayer": "Map Layer", + "mapCustom": "Custom Map", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps Key", + "mapBingRoad": "Bing Maps Road", + "mapBingAerial": "Bing Maps Aerial", + "stateTitle": "State", + "stateName": "Attribute", + "stateValue": "Value", + "commandTitle": "Command", + "commandSend": "Send", + "commandType": "Type", + "commandSent": "Command has been sent", + "commandPositionPeriodic": "Periodic Reporting", + "commandPositionStop": "Stop Reporting", + "commandEngineStop": "Engine Stop", + "commandEngineResume": "Engine Resume", + "commandFrequency": "Frequency", + "commandUnit": "Unit" +}
\ No newline at end of file diff --git a/web/l10n/es.js b/web/l10n/es.js deleted file mode 100644 index ff5fbb7ab..000000000 --- a/web/l10n/es.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: 'Cargando...', - sharedSave: 'Grabar', - sharedCancel: 'Cancelar', - sharedAdd: 'Agregar', - sharedEdit: 'Editar', - sharedRemove: 'Borrar', - sharedRemoveConfirm: 'Borrar elemento?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'Hora', - sharedMinute: 'Minuto', - sharedSecond: 'Segundos', - - errorTitle: 'Error', - errorUnknown: 'Error Desconocido', - - userName: 'Nombre', - userEmail: 'Email', - userPassword: 'Contraseña', - userAdmin: 'Admin', - - loginTitle: 'Ingresar', - loginLanguage: 'Lenguaje', - loginRegister: 'Registrar', - loginLogin: 'Ingresar', - loginFailed: 'Direccion de correo o Contraseña Incorrecta', - loginCreated: 'Nuevo usuario ha sido registrado', - loginLogout: 'Salir', - - deviceDialog: 'Dispositivo', - deviceTitle: 'Dispositivos', - deviceName: 'Nombre', - deviceIdentifier: 'Identificador', - deviceCommand: 'Comando', - - settingsTitle: 'Preferencias', - settingsUser: 'Cuenta', - settingsServer: 'Servidor', - settingsUsers: 'Usuarios', - settingsDistanceUnit: 'Distancia', - settingsSpeedUnit: 'Velocidad', - - reportTitle: 'Reportes', - reportDevice: 'Dispositivos', - reportFrom: 'Desde', - reportTo: 'Hasta', - reportShow: 'Mostrar', - reportClear: 'Limpiar', - - positionTime: 'Hora', - positionValid: 'Valida', - positionLatitude: 'Latitud', - positionLongitude: 'Longitud', - positionAltitude: 'Altitud', - positionSpeed: 'Velocidad', - positionCourse: 'Curso', - positionAddress: 'Direccion', - positionProtocol: 'Protocolo', - - serverTitle: 'Preferencias Servidor', - serverZoom: 'Zoom', - serverRegistration: 'Registrar', - - mapTitle: 'Mapa', - mapLayer: 'Capa de Mapa', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Maps - Carretera', - mapBingAerial: 'Bing Maps - Aereo', - - stateTitle: 'Estado', - stateName: 'Parametro', - stateValue: 'Valor', - - commandTitle: 'Comando', - commandSend: 'Enviar', - commandType: 'Tipo', - commandPositionPeriodic: 'Frecuencia de posiciones', - commandPositionStop: 'Detener reporte de posiciones', - commandEngineStop: 'Apagar motor', - commandEngineResume: 'Desbloquear encendido de motor', - commandFrequency: 'Frequencia', - commandUnit: 'Unidad' -}; diff --git a/web/l10n/es.json b/web/l10n/es.json new file mode 100644 index 000000000..79bf0dbc8 --- /dev/null +++ b/web/l10n/es.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Cargando...", + "sharedSave": "Grabar", + "sharedCancel": "Cancelar", + "sharedAdd": "Agregar", + "sharedEdit": "Editar", + "sharedRemove": "Borrar", + "sharedRemoveConfirm": "Borrar Elemento?", + "sharedKm": "KM", + "sharedMi": "MI", + "sharedKmh": "KM/H", + "sharedMph": "MPH", + "sharedHour": "Hora", + "sharedMinute": "Minuto", + "sharedSecond": "Segundos", + "errorTitle": "Error", + "errorUnknown": "Error Desconocido", + "errorConnection": "Error de Conexión", + "userName": "Nombre", + "userEmail": "Email", + "userPassword": "Contraseña", + "userAdmin": "Admin", + "loginTitle": "Ingresar", + "loginLanguage": "Idioma", + "loginRegister": "Registrar", + "loginLogin": "Ingresar", + "loginFailed": "Dirección de Correo o Contraseña Incorrecta", + "loginCreated": "Nuevo Usuario ha sido registrado", + "loginLogout": "Salir", + "deviceDialog": "Dispositivo", + "deviceTitle": "Dispositivos", + "deviceName": "Nombre", + "deviceIdentifier": "Identificador", + "deviceCommand": "Comando", + "settingsTitle": "Preferencias", + "settingsUser": "Cuenta", + "settingsServer": "Servidor", + "settingsUsers": "Usuarios", + "settingsDistanceUnit": "Distancia", + "settingsSpeedUnit": "Velocidad", + "reportTitle": "Reportes", + "reportDevice": "Dispositivos", + "reportFrom": "Desde", + "reportTo": "Hasta", + "reportShow": "Mostrar", + "reportClear": "Limpiar", + "positionFixTime": "Hora", + "positionValid": "Válida", + "positionLatitude": "Latitud", + "positionLongitude": "Longitud", + "positionAltitude": "Altitud", + "positionSpeed": "Velocidad", + "positionCourse": "Curso", + "positionAddress": "Dirección", + "positionProtocol": "Protocolo", + "serverTitle": "Preferencias Servidor", + "serverZoom": "Zoom", + "serverRegistration": "Registrar", + "mapTitle": "Mapa", + "mapLayer": "Capa de Mapa", + "mapCustom": "Mapa Personalizado", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps Key", + "mapBingRoad": "Bing Maps - Carretera", + "mapBingAerial": "Bing Maps - Aéreo", + "stateTitle": "Estado", + "stateName": "Parámetro", + "stateValue": "Valor", + "commandTitle": "Comando", + "commandSend": "Enviar", + "commandType": "Tipo", + "commandSent": "El Comando ha sido enviado", + "commandPositionPeriodic": "Frecuencia de Posiciones", + "commandPositionStop": "Detener Reporte de Posiciones", + "commandEngineStop": "Apagar motor", + "commandEngineResume": "Desbloquear Encendido de Motor", + "commandFrequency": "Frequencia", + "commandUnit": "Unidad" +}
\ No newline at end of file diff --git a/web/l10n/fr.js b/web/l10n/fr.js deleted file mode 100644 index 7d1541c22..000000000 --- a/web/l10n/fr.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: 'Chargement...', - sharedSave: 'Enregistrer', - sharedCancel: 'Annuler', - sharedAdd: 'Ajouter', - sharedEdit: 'Editer', - sharedRemove: 'Effacer', - sharedRemoveConfirm: 'Effacer item?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'Heure', - sharedMinute: 'Minute', - sharedSecond: 'Seconde', - - errorTitle: 'Erreur', - errorUnknown: 'Erreur inconnue', - - userName: 'Nom', - userEmail: 'Email', - userPassword: 'Mot de Passe', - userAdmin: 'Admin', - - loginTitle: 'Identification', - loginLanguage: 'Langue', - loginRegister: 'Inscription', - loginLogin: 'Se connecter', - loginFailed: 'Adresse email ou mot de passe incorrect', - loginCreated: 'New user has been registered', - loginLogout: 'Déconnection', - - deviceDialog: 'Dispositif', - deviceTitle: 'Dispositifs', - deviceName: 'Nom', - deviceIdentifier: 'Identifiant', - deviceCommand: 'Commande', - - settingsTitle: 'Configurations', - settingsUser: 'Compte', - settingsServer: 'Serveur', - settingsUsers: 'Utilisateurs', - settingsDistanceUnit: 'Distance', - settingsSpeedUnit: 'Vitesse', - - reportTitle: 'Rapports', - reportDevice: 'Dispositif', - reportFrom: 'De', - reportTo: 'A', - reportShow: 'Afficher', - reportClear: 'Effacer', - - positionTime: 'Heure', - positionValid: 'Valide', - positionLatitude: 'Latitude', - positionLongitude: 'Longitude', - positionAltitude: 'Altitude', - positionSpeed: 'Vitesse', - positionCourse: 'Sense', - positionAddress: 'Adresse', - positionProtocol: 'Protocole', - - serverTitle: 'Configurations du Serveur Settings', - serverZoom: 'Zoom', - serverRegistration: 'Inscription', - - mapTitle: 'Carte', - mapLayer: 'Cartes', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Maps Road', - mapBingAerial: 'Bing Maps Aerial', - - stateTitle: 'Etat', - stateName: 'Paramètre', - stateValue: 'Valeur', - - commandTitle: 'Commande', - commandSend: 'Envoyer', - commandType: 'Type', - commandPositionPeriodic: 'Périodicité du rapport de position', - commandPositionStop: 'Arrêt du rapport de position', - commandEngineStop: 'Moteur arrêter', - commandEngineResume: 'Moteur démarrer', - commandFrequency: 'Fréquence', - commandUnit: 'Unité' -}; diff --git a/web/l10n/fr.json b/web/l10n/fr.json new file mode 100644 index 000000000..0b18a008b --- /dev/null +++ b/web/l10n/fr.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Chargement...", + "sharedSave": "Enregistrer", + "sharedCancel": "Annuler", + "sharedAdd": "Ajouter", + "sharedEdit": "Editer", + "sharedRemove": "Effacer", + "sharedRemoveConfirm": "Effacer item?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "Heure", + "sharedMinute": "Minute", + "sharedSecond": "Seconde", + "errorTitle": "Erreur", + "errorUnknown": "Erreur inconnue", + "errorConnection": "erreur de connection", + "userName": "Nom", + "userEmail": "Email", + "userPassword": "Mot de Passe", + "userAdmin": "Admin", + "loginTitle": "Identification", + "loginLanguage": "Langue", + "loginRegister": "Inscription", + "loginLogin": "Se connecter", + "loginFailed": "Adresse email ou mot de passe incorrect", + "loginCreated": "New user has been registered", + "loginLogout": "Déconnection", + "deviceDialog": "Dispositif", + "deviceTitle": "Dispositifs", + "deviceName": "Nom", + "deviceIdentifier": "Identifiant", + "deviceCommand": "Commande", + "settingsTitle": "Configurations", + "settingsUser": "Compte", + "settingsServer": "Serveur", + "settingsUsers": "Utilisateurs", + "settingsDistanceUnit": "Distance", + "settingsSpeedUnit": "Vitesse", + "reportTitle": "Rapports", + "reportDevice": "Dispositif", + "reportFrom": "De", + "reportTo": "A", + "reportShow": "Afficher", + "reportClear": "Effacer", + "positionFixTime": "Heure", + "positionValid": "Valide", + "positionLatitude": "Latitude", + "positionLongitude": "Longitude", + "positionAltitude": "Altitude", + "positionSpeed": "Vitesse", + "positionCourse": "Sense", + "positionAddress": "Adresse", + "positionProtocol": "Protocole", + "serverTitle": "Configurations du Serveur Settings", + "serverZoom": "Zoom", + "serverRegistration": "Inscription", + "mapTitle": "Carte", + "mapLayer": "Cartes", + "mapCustom": "Carte personnalisée", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Map Key", + "mapBingRoad": "Bing Maps Road", + "mapBingAerial": "Bing Maps Aerial", + "stateTitle": "Etat", + "stateName": "Paramètre", + "stateValue": "Valeur", + "commandTitle": "Commande", + "commandSend": "Envoyer", + "commandType": "Type", + "commandSent": "Commande envoyée", + "commandPositionPeriodic": "Périodicité du rapport de position", + "commandPositionStop": "Arrêt du rapport de position", + "commandEngineStop": "Moteur arrêter", + "commandEngineResume": "Moteur démarrer", + "commandFrequency": "Fréquence", + "commandUnit": "Unité" +}
\ No newline at end of file diff --git a/web/l10n/hu.js b/web/l10n/hu.js deleted file mode 100755 index b8d965e4a..000000000 --- a/web/l10n/hu.js +++ /dev/null @@ -1,87 +0,0 @@ -var strings = { - sharedLoading: 'Betöltés...', - sharedSave: 'Mentés', - sharedCancel: 'Mégse', - sharedAdd: 'Hozzáadás', - sharedEdit: 'Szerkesztés', - sharedRemove: 'Törlés', - sharedRemoveConfirm: 'Biztosan törli?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'Óra', - sharedMinute: 'Perc', - sharedSecond: 'Másodperc', - - errorTitle: 'Hiba', - errorUnknown: 'Ismeretlen hiba.', - - userName: 'Név', - userEmail: 'Email', - userPassword: 'Jelszó', - userAdmin: 'Adminisztrátor', - - loginTitle: 'Bejelentkezés', - loginLanguage: 'Nyelv', - loginRegister: 'Regisztráció', - loginLogin: 'Bejelentkezés', - loginFailed: 'Hibás email vagy jelszó', - loginCreated: 'Az új felhasználó sikeresen létrehozva', - loginLogout: 'Kilépés', - - deviceDialog: 'Eszköz', - deviceTitle: 'Eszközök', - deviceName: 'Eszköznév', - deviceIdentifier: 'Azonosító', - deviceCommand: 'Parancs', - - settingsTitle: 'Beállítások', - settingsUser: 'Fiók', - settingsServer: 'Szerver', - settingsUsers: 'Felhasználók', - settingsDistanceUnit: 'Távolság', - settingsSpeedUnit: 'Sebesség', - - reportTitle: 'Jelentések', - reportDevice: 'Eszköz', - reportFrom: 'Kezdő dátum:', - reportTo: 'Végső dátum:', - reportShow: 'Mutat', - reportClear: 'Töröl', - - positionTime: 'Idő', - positionValid: 'Valós', - positionLatitude: 'Szélességi fok', - positionLongitude: 'Hosszúsági fok', - positionAltitude: 'Magasság', - positionSpeed: 'Sebesség', - positionCourse: 'Irány', - positionAddress: 'Cím', - positionProtocol: 'Protokoll', - - serverTitle: 'Szerver beállítások', - serverZoom: 'Nagyítás', - serverRegistration: 'Regisztráció', - - mapTitle: 'Térkép', - mapLayer: 'Térkép réteg', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Maps Road', - mapBingAerial: 'Bing Maps Aerial', - - stateTitle: 'Helyzet', - stateName: 'Paraméter', - stateValue: 'Érték', - - commandTitle: 'Parancs', - commandSend: 'Küld', - commandType: 'Típus', - commandSent: 'A parancs elküldve', - commandPositionPeriodic: 'Pozició küldés', - commandPositionStop: 'Pozició küldés vége', - commandEngineStop: 'Motor letiltás', - commandEngineResume: 'Motor engedélyezés', - commandFrequency: 'Frekvencia', - commandUnit: 'Egység' -}; diff --git a/web/l10n/hu.json b/web/l10n/hu.json new file mode 100644 index 000000000..8fb48a830 --- /dev/null +++ b/web/l10n/hu.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Betöltés...", + "sharedSave": "Mentés", + "sharedCancel": "Mégse", + "sharedAdd": "Hozzáadás", + "sharedEdit": "Szerkesztés", + "sharedRemove": "Törlés", + "sharedRemoveConfirm": "Biztosan törli?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "Óra", + "sharedMinute": "Perc", + "sharedSecond": "Másodperc", + "errorTitle": "Hiba", + "errorUnknown": "Ismeretlen hiba", + "errorConnection": "Kapcsolódási hiba", + "userName": "Név", + "userEmail": "Email", + "userPassword": "Jelszó", + "userAdmin": "Adminisztrátor", + "loginTitle": "Bejelentkezés", + "loginLanguage": "Nyelv", + "loginRegister": "Regisztráció", + "loginLogin": "Bejelentkezés", + "loginFailed": "Hibás email vagy jelszó", + "loginCreated": "Az új felhasználó sikeresen létrehozva", + "loginLogout": "Kilépés", + "deviceDialog": "Eszköz", + "deviceTitle": "Eszközök", + "deviceName": "Eszköznév", + "deviceIdentifier": "Azonosító", + "deviceCommand": "Parancs", + "settingsTitle": "Beállítások", + "settingsUser": "Fiók", + "settingsServer": "Szerver", + "settingsUsers": "Felhasználók", + "settingsDistanceUnit": "Távolság", + "settingsSpeedUnit": "Sebesség", + "reportTitle": "Jelentések", + "reportDevice": "Eszköz", + "reportFrom": "Kezdő dátum:", + "reportTo": "Végső dátum:", + "reportShow": "Mutat", + "reportClear": "Töröl", + "positionFixTime": "Idő", + "positionValid": "Valós", + "positionLatitude": "Szélességi fok", + "positionLongitude": "Hosszúsági fok", + "positionAltitude": "Magasság", + "positionSpeed": "Sebesség", + "positionCourse": "Irány", + "positionAddress": "Cím", + "positionProtocol": "Protokoll", + "serverTitle": "Szerver beállítások", + "serverZoom": "Nagyítás", + "serverRegistration": "Regisztráció", + "mapTitle": "Térkép", + "mapLayer": "Térkép réteg", + "mapCustom": "Egyéni térkép", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps kulcs", + "mapBingRoad": "Bing Maps Road", + "mapBingAerial": "Bing Maps Aerial", + "stateTitle": "Helyzet", + "stateName": "Paraméter", + "stateValue": "Érték", + "commandTitle": "Parancs", + "commandSend": "Küld", + "commandType": "Típus", + "commandSent": "A parancs elküldve", + "commandPositionPeriodic": "Pozició küldés", + "commandPositionStop": "Pozició küldés vége", + "commandEngineStop": "Motor letiltás", + "commandEngineResume": "Motor engedélyezés", + "commandFrequency": "Frekvencia", + "commandUnit": "Egység" +}
\ No newline at end of file diff --git a/web/l10n/lt.js b/web/l10n/lt.js deleted file mode 100644 index 1ff138d65..000000000 --- a/web/l10n/lt.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: 'Kraunasi..', - sharedSave: 'Išsaugoti', - sharedCancel: 'Atšaukti', - sharedAdd: 'Pridėti', - sharedEdit: 'Redaguoti', - sharedRemove: 'Ištrinti', - sharedRemoveConfirm: 'Ar tikrais norite ištrinti?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'Valanda(-os)', - sharedMinute: 'Minutė(-es)', - sharedSecond: 'Sekundė(-es)', - - errorTitle: 'Klaida', - errorUnknown: 'Nenumatyta klaida', - - userName: 'Prisijungimo vardas', - userEmail: 'Vartotojo vardas', - userPassword: 'Slaptažodis', - userAdmin: 'Administratorius', - - loginTitle: 'Prisijungimas', - loginLanguage: 'Kalba', - loginRegister: 'Registruotis', - loginLogin: 'Prisijungti', - loginFailed: 'Neteisingas el.paštas ir/ar slaptažodis', - loginCreated: 'Registracija sėmkinga', - loginLogout: 'Atsijungti', - - deviceDialog: 'Prietaisas', - deviceTitle: 'Prietaisai', - deviceName: 'Pavadinimas', - deviceIdentifier: 'Identifikacinis kodas', - deviceCommand: 'Komanda', - - settingsTitle: 'Nustatymai', - settingsUser: 'Paskyra', - settingsServer: 'Serveris', - settingsUsers: 'Vartotojai', - settingsDistanceUnit: 'Atstumas', - settingsSpeedUnit: 'Greitis', - - reportTitle: 'Ataskaita', - reportDevice: 'Prietaisas', - reportFrom: 'Nuo', - reportTo: 'Iki', - reportShow: 'Rodyti', - reportClear: 'Valyti', - - positionTime: 'Laikas', - positionValid: 'Galimas', - positionLatitude: 'Platuma', - positionLongitude: 'Ilguma', - positionAltitude: 'Aukštis', - positionSpeed: 'Greitis', - positionCourse: 'Eiga', - positionAddress: 'Adresas', - positionProtocol: 'Protokolas', - - serverTitle: 'Serverio nustatymai', - serverZoom: 'Priartinimas', - serverRegistration: 'Registracija', - - mapTitle: 'Žemėlapis', - mapLayer: 'Žemėlapio sluoksnis', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Maps Road', - mapBingAerial: 'Bing Maps Aerial', - - stateTitle: 'Statusas', - stateName: 'Parametras', - stateValue: 'Reikšmė', - - commandTitle: 'Komanda', - commandSend: 'Siūsti', - commandType: 'Tipas', - commandPositionPeriodic: 'Periodinis reportavimas', - commandPositionStop: 'Stabdyti reportavimą', - commandEngineStop: 'Stabdyti variklį', - commandEngineResume: 'Paleisti variklį', - commandFrequency: 'Dažnis', - commandUnit: 'Vienetai' -}; diff --git a/web/l10n/lt.json b/web/l10n/lt.json new file mode 100644 index 000000000..85cdacb73 --- /dev/null +++ b/web/l10n/lt.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Kraunasi..", + "sharedSave": "Išsaugoti", + "sharedCancel": "Atšaukti", + "sharedAdd": "Pridėti", + "sharedEdit": "Redaguoti", + "sharedRemove": "Ištrinti", + "sharedRemoveConfirm": "Ar tikrais norite ištrinti?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "Valanda(-os)", + "sharedMinute": "Minutė(-es)", + "sharedSecond": "Sekundė(-es)", + "errorTitle": "Klaida", + "errorUnknown": "Nenumatyta klaida", + "errorConnection": "Ryšio klaida", + "userName": "Prisijungimo vardas", + "userEmail": "Vartotojo vardas", + "userPassword": "Slaptažodis", + "userAdmin": "Administratorius", + "loginTitle": "Prisijungimas", + "loginLanguage": "Kalba", + "loginRegister": "Registruotis", + "loginLogin": "Prisijungti", + "loginFailed": "Neteisingas el.paštas ir/ar slaptažodis", + "loginCreated": "Registracija sėmkinga", + "loginLogout": "Atsijungti", + "deviceDialog": "Prietaisas", + "deviceTitle": "Prietaisai", + "deviceName": "Pavadinimas", + "deviceIdentifier": "Identifikacinis kodas", + "deviceCommand": "Komanda", + "settingsTitle": "Nustatymai", + "settingsUser": "Paskyra", + "settingsServer": "Serveris", + "settingsUsers": "Vartotojai", + "settingsDistanceUnit": "Atstumas", + "settingsSpeedUnit": "Greitis", + "reportTitle": "Ataskaita", + "reportDevice": "Prietaisas", + "reportFrom": "Nuo", + "reportTo": "Iki", + "reportShow": "Rodyti", + "reportClear": "Valyti", + "positionFixTime": "Laikas", + "positionValid": "Galimas", + "positionLatitude": "Platuma", + "positionLongitude": "Ilguma", + "positionAltitude": "Aukštis", + "positionSpeed": "Greitis", + "positionCourse": "Eiga", + "positionAddress": "Adresas", + "positionProtocol": "Protokolas", + "serverTitle": "Serverio nustatymai", + "serverZoom": "Priartinimas", + "serverRegistration": "Registracija", + "mapTitle": "Žemėlapis", + "mapLayer": "Žemėlapio sluoksnis", + "mapCustom": "Pasirinktinis Žemėlapis", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps raktas", + "mapBingRoad": "Bing Maps Road", + "mapBingAerial": "Bing Maps Aerial", + "stateTitle": "Statusas", + "stateName": "Parametras", + "stateValue": "Reikšmė", + "commandTitle": "Komanda", + "commandSend": "Siūsti", + "commandType": "Tipas", + "commandSent": "Komanda buvo išsiųstas", + "commandPositionPeriodic": "Periodinis reportavimas", + "commandPositionStop": "Stabdyti reportavimą", + "commandEngineStop": "Stabdyti variklį", + "commandEngineResume": "Paleisti variklį", + "commandFrequency": "Dažnis", + "commandUnit": "Vienetai" +}
\ No newline at end of file diff --git a/web/l10n/nl.js b/web/l10n/nl.js deleted file mode 100644 index b51040068..000000000 --- a/web/l10n/nl.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: 'Laden...', - sharedSave: 'Opslaan', - sharedCancel: 'Annuleren', - sharedAdd: 'Toevoegen', - sharedEdit: 'Bewerken', - sharedRemove: 'Verwijderen', - sharedRemoveConfirm: 'Verwijder item?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'Uur', - sharedMinute: 'Minuut', - sharedSecond: 'Seconde', - - errorTitle: 'Fout', - errorUnknown: 'Onbekende fout', - - userName: 'Gebruikersnaam', - userEmail: 'Email', - userPassword: 'WachtwoordPassword', - userAdmin: 'Admin', - - loginTitle: 'Inloggen', - loginLanguage: 'Taal', - loginRegister: 'Registeren', - loginLogin: 'Inloggen', - loginFailed: 'Onjuiste emailadres of wachtwoord', - loginCreated: 'Nieuwe gebruiker is geregistreerd', - loginLogout: 'Uitloggen', - - deviceDialog: 'Apparaat', - deviceTitle: 'Apparaten', - deviceName: 'Naam', - deviceIdentifier: 'Identifier', - deviceCommand: 'Commando', - - settingsTitle: 'Instellingen', - settingsUser: 'Account', - settingsServer: 'Server', - settingsUsers: 'Gebruikers', - settingsDistanceUnit: 'Afstand', - settingsSpeedUnit: 'Snelheid', - - reportTitle: 'Reports', - reportDevice: 'Apparaat', - reportFrom: 'Van', - reportTo: 'Naar', - reportShow: 'Laten zien', - reportClear: 'Leegmaken', - - positionTime: 'Tijd', - positionValid: 'Geldig', - positionLatitude: 'Latitude', - positionLongitude: 'Longitude', - positionAltitude: 'Altitude', - positionSpeed: 'Snelheid', - positionCourse: 'Koers', - positionAddress: 'Adres', - positionProtocol: 'Protocol', - - serverTitle: 'Server Instellingen', - serverZoom: 'Zoom', - serverRegistration: 'Registratie', - - mapTitle: 'Kaart', - mapLayer: 'Kaart laag', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Maps Wegen', - mapBingAerial: 'Bing Maps Luchtfoto', - - stateTitle: 'Status', - stateName: 'Parameter', - stateValue: 'Waarde', - - commandTitle: 'Commando', - commandSend: 'Verstuur', - commandType: 'Type', - commandPositionPeriodic: 'Periodic Reporting', - commandPositionStop: 'Stop Reporting', - commandEngineStop: 'Engine Stop', - commandEngineResume: 'Engine Resume', - commandFrequency: 'Frequentie', - commandUnit: 'Eenheid' -}; diff --git a/web/l10n/nl.json b/web/l10n/nl.json new file mode 100644 index 000000000..53b12fa54 --- /dev/null +++ b/web/l10n/nl.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Laden...", + "sharedSave": "Opslaan", + "sharedCancel": "Annuleren", + "sharedAdd": "Toevoegen", + "sharedEdit": "Bewerken", + "sharedRemove": "Verwijderen", + "sharedRemoveConfirm": "Verwijder item?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "Uur", + "sharedMinute": "Minuut", + "sharedSecond": "Seconde", + "errorTitle": "Fout", + "errorUnknown": "Onbekende fout", + "errorConnection": "Verbindingsfout", + "userName": "Gebruikersnaam", + "userEmail": "Email", + "userPassword": "WachtwoordPassword", + "userAdmin": "Admin", + "loginTitle": "Inloggen", + "loginLanguage": "Taal", + "loginRegister": "Registeren", + "loginLogin": "Inloggen", + "loginFailed": "Onjuiste emailadres of wachtwoord", + "loginCreated": "Nieuwe gebruiker is geregistreerd", + "loginLogout": "Uitloggen", + "deviceDialog": "Apparaat", + "deviceTitle": "Apparaten", + "deviceName": "Naam", + "deviceIdentifier": "Identifier", + "deviceCommand": "Commando", + "settingsTitle": "Instellingen", + "settingsUser": "Account", + "settingsServer": "Server", + "settingsUsers": "Gebruikers", + "settingsDistanceUnit": "Afstand", + "settingsSpeedUnit": "Snelheid", + "reportTitle": "Reports", + "reportDevice": "Apparaat", + "reportFrom": "Van", + "reportTo": "Naar", + "reportShow": "Laten zien", + "reportClear": "Leegmaken", + "positionFixTime": "Tijd", + "positionValid": "Geldig", + "positionLatitude": "Latitude", + "positionLongitude": "Longitude", + "positionAltitude": "Altitude", + "positionSpeed": "Snelheid", + "positionCourse": "Koers", + "positionAddress": "Adres", + "positionProtocol": "Protocol", + "serverTitle": "Server Instellingen", + "serverZoom": "Zoom", + "serverRegistration": "Registratie", + "mapTitle": "Kaart", + "mapLayer": "Kaart laag", + "mapCustom": "Aangepaste Map", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps sleutel", + "mapBingRoad": "Bing Maps Wegen", + "mapBingAerial": "Bing Maps Luchtfoto", + "stateTitle": "Status", + "stateName": "Parameter", + "stateValue": "Waarde", + "commandTitle": "Commando", + "commandSend": "Verstuur", + "commandType": "Type", + "commandSent": "Commando Verstuurd", + "commandPositionPeriodic": "Periodic Reporting", + "commandPositionStop": "Stop Reporting", + "commandEngineStop": "Engine Stop", + "commandEngineResume": "Engine Resume", + "commandFrequency": "Frequentie", + "commandUnit": "Eenheid" +}
\ No newline at end of file diff --git a/web/l10n/pl.js b/web/l10n/pl.js deleted file mode 100644 index 238dd33bf..000000000 --- a/web/l10n/pl.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: 'Wczytywanie...', - sharedSave: 'Zapisz', - sharedCancel: 'Anuluj', - sharedAdd: 'Dodaj', - sharedEdit: 'Edytuj', - sharedRemove: 'Usuń', - sharedRemoveConfirm: 'Usuń obiekt?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'Godzina', - sharedMinute: 'Minuta', - sharedSecond: 'Sekunda', - - errorTitle: 'Bląd', - errorUnknown: 'Nieznany błąd', - - userName: 'Nazwa', - userEmail: 'Email', - userPassword: 'Hasło', - userAdmin: 'Administrator', - - loginTitle: 'Logowanie', - loginLanguage: 'Język', - loginRegister: 'Rejestracja', - loginLogin: 'Zaloguj', - loginFailed: 'Nieprawidłowy adres e-mail lub hasło', - loginCreated: 'Nowy użytkownik został zarejestrowany', - loginLogout: 'Wyloguj', - - deviceDialog: 'Urządzenie', - deviceTitle: 'Urządzenia', - deviceName: 'Nazwa', - deviceIdentifier: 'Identyfikator', - deviceCommand: 'Zdarzenie', - - settingsTitle: 'Ustawienia', - settingsUser: 'Konto', - settingsServer: 'Serwer', - settingsUsers: 'Użytkownicy', - settingsDistanceUnit: 'Dystans', - settingsSpeedUnit: 'Prędkość', - - reportTitle: 'Raporty', - reportDevice: 'Urządzenie', - reportFrom: 'Z', - reportTo: 'Do', - reportShow: 'Wczytaj', - reportClear: 'Wyczyść', - - positionTime: 'Czas', - positionValid: 'Aktywny', - positionLatitude: 'Szerokość', - positionLongitude: 'Długość', - positionAltitude: 'Wysokość', - positionSpeed: 'Prędkość', - positionCourse: 'Kurs', - positionAddress: 'Adres', - positionProtocol: 'Protokół', - - serverTitle: 'Ustawienia serwera', - serverZoom: 'Powiększenie', - serverRegistration: 'Rejestracja', - - mapTitle: 'Mapa', - mapLayer: 'Mapa', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Maps Road', - mapBingAerial: 'Bing Maps Aerial', - - stateTitle: 'Lokalizacja', - stateName: 'Właściwości', - stateValue: 'Wartość', - - commandTitle: 'Zdarzenie', - commandSend: 'Wyślij', - commandType: 'Typ', - commandPositionPeriodic: 'Pozycja - Fix', - commandPositionStop: 'Pozycja - Stop', - commandEngineStop: 'Silnik - Stop', - commandEngineResume: 'Silnik - Praca', - commandFrequency: 'Częstotliwość', - commandUnit: 'Jednostka' -}; diff --git a/web/l10n/pl.json b/web/l10n/pl.json new file mode 100644 index 000000000..dbfe45831 --- /dev/null +++ b/web/l10n/pl.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Wczytywanie...", + "sharedSave": "Zapisz", + "sharedCancel": "Anuluj", + "sharedAdd": "Dodaj", + "sharedEdit": "Edytuj", + "sharedRemove": "Usuń", + "sharedRemoveConfirm": "Usuń obiekt?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "Godzina", + "sharedMinute": "Minuta", + "sharedSecond": "Sekunda", + "errorTitle": "Bląd", + "errorUnknown": "Nieznany błąd", + "errorConnection": "Błąd przy połączeniu", + "userName": "Nazwa", + "userEmail": "Email", + "userPassword": "Hasło", + "userAdmin": "Administrator", + "loginTitle": "Logowanie", + "loginLanguage": "Język", + "loginRegister": "Rejestracja", + "loginLogin": "Zaloguj", + "loginFailed": "Nieprawidłowy adres e-mail lub hasło", + "loginCreated": "Nowy użytkownik został zarejestrowany", + "loginLogout": "Wyloguj", + "deviceDialog": "Urządzenie", + "deviceTitle": "Urządzenia", + "deviceName": "Nazwa", + "deviceIdentifier": "Identyfikator", + "deviceCommand": "Zdarzenie", + "settingsTitle": "Ustawienia", + "settingsUser": "Konto", + "settingsServer": "Serwer", + "settingsUsers": "Użytkownicy", + "settingsDistanceUnit": "Dystans", + "settingsSpeedUnit": "Prędkość", + "reportTitle": "Raporty", + "reportDevice": "Urządzenie", + "reportFrom": "Z", + "reportTo": "Do", + "reportShow": "Wczytaj", + "reportClear": "Wyczyść", + "positionFixTime": "Czas", + "positionValid": "Aktywny", + "positionLatitude": "Szerokość", + "positionLongitude": "Długość", + "positionAltitude": "Wysokość", + "positionSpeed": "Prędkość", + "positionCourse": "Kurs", + "positionAddress": "Adres", + "positionProtocol": "Protokół", + "serverTitle": "Ustawienia serwera", + "serverZoom": "Powiększenie", + "serverRegistration": "Rejestracja", + "mapTitle": "Mapa", + "mapLayer": "Mapa", + "mapCustom": "Własna mapa", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps Key", + "mapBingRoad": "Bing Maps Road", + "mapBingAerial": "Bing Maps Aerial", + "stateTitle": "Lokalizacja", + "stateName": "Właściwości", + "stateValue": "Wartość", + "commandTitle": "Zdarzenie", + "commandSend": "Wyślij", + "commandType": "Typ", + "commandSent": "Komenda została wysłana", + "commandPositionPeriodic": "Pozycja - Fix", + "commandPositionStop": "Pozycja - Stop", + "commandEngineStop": "Silnik - Stop", + "commandEngineResume": "Silnik - Praca", + "commandFrequency": "Częstotliwość", + "commandUnit": "Jednostka" +}
\ No newline at end of file diff --git a/web/l10n/pt.js b/web/l10n/pt.js deleted file mode 100644 index 6155b2312..000000000 --- a/web/l10n/pt.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: 'Carregando ...', - sharedSave: 'Salvar', - sharedCancel: 'Cancelar', - sharedAdd: 'Adicionar', - sharedEdit: 'Editar', - sharedRemove: 'Remover', - sharedRemoveConfirm: 'Remove item?', - sharedKm: 'Km', - sharedMi: 'mi', - sharedKmh: 'Km/h', - sharedMph: 'Mph', - sharedHour: 'Hora', - sharedMinute: 'Minuto', - sharedSecond: 'Segundo', - - errorTitle: 'Erro', - errorUnknown: 'Erro desconhecido', - - userName: 'Nome', - userEmail: 'E-mail', - userPassword: 'Senha', - userAdmin: 'Admin', - - loginTitle: 'Entrar', - loginLanguage: 'Idioma', - loginRegister: 'Registrar', - loginLogin: 'Entrar', - loginFailed: 'Endereço de e-mail ou senha incorreta', - loginCreated: 'Novo usuário foi registrado', - loginLogout: 'Sair', - - deviceDialog: 'Dispositivo', - deviceTitle: 'Devices', - deviceName: 'Nome', - deviceIdentifier: 'Identificador', - deviceCommand: 'Comando', - - settingsTitle: 'Configurações', - settingsUser: 'Conta', - settingsServer: 'Servidor', - settingsUsers: 'Usuário', - settingsDistanceUnit: 'Distância', - settingsSpeedUnit: 'Velocidade', - - reportTitle: 'Relatórios', - reportDevice: 'Dispositivo', - reportFrom: 'De', - reportTo: 'Para', - reportShow: 'Mostrar', - reportClear: 'Limpar', - - positionTime: 'Tempo', - positionValid: 'Válido', - positionLatitude: 'Latitude', - positionLongitude: 'Longitude', - positionAltitude: 'Altitude', - positionSpeed: 'Velocidade', - positionCourse: 'Course', - positionAddress: 'Endereço', - positionProtocol: 'protocolo', - - serverTitle: 'Configurações do Servidor', - serverZoom: 'Zoom', - serverRegistration: 'Registro', - - mapTitle: 'Mapa', - mapLayer: 'Camada Mapa', - mapOsm: 'Open Street Mapa', - mapBingRoad: 'Bing Mapas Estrada', - mapBingAerial: 'Bing Mapas Aérea', - - stateTitle: 'Estado', - stateName: 'Parâmetro', - stateValue: 'Valor', - - commandTitle: 'Comando', - commandSend: 'Enviar', - commandType: 'Tipo', - commandPositionPeriodic: 'Posição Tempo', - commandPositionStop: 'Parar Posição', - commandEngineStop: 'Bloqueio Veículo', - commandEngineResume: 'Desbloqueio Veículo', - commandFrequency: 'Frequência', - commandUnit: 'Unidade' -}; diff --git a/web/l10n/pt.json b/web/l10n/pt.json new file mode 100644 index 000000000..b3e3619c4 --- /dev/null +++ b/web/l10n/pt.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Carregando...", + "sharedSave": "Salvar", + "sharedCancel": "Cancelar", + "sharedAdd": "Adicionar", + "sharedEdit": "Editar", + "sharedRemove": "Remover", + "sharedRemoveConfirm": "Remover item?", + "sharedKm": "Km", + "sharedMi": "mi", + "sharedKmh": "Km/h", + "sharedMph": "Mph", + "sharedHour": "Hora", + "sharedMinute": "Minuto", + "sharedSecond": "Segundo", + "errorTitle": "Erro", + "errorUnknown": "Erro desconhecido", + "errorConnection": "Erro de conexão", + "userName": "Nome", + "userEmail": "E-mail", + "userPassword": "Senha", + "userAdmin": "Admin", + "loginTitle": "Entrar", + "loginLanguage": "Idioma", + "loginRegister": "Registrar", + "loginLogin": "Entrar", + "loginFailed": "Endereço de e-mail ou senha incorreta", + "loginCreated": "Novo usuário foi registrado", + "loginLogout": "Sair", + "deviceDialog": "Dispositivo", + "deviceTitle": "Devices", + "deviceName": "Nome", + "deviceIdentifier": "Identificador", + "deviceCommand": "Comando", + "settingsTitle": "Configurações", + "settingsUser": "Conta", + "settingsServer": "Servidor", + "settingsUsers": "Usuário", + "settingsDistanceUnit": "Distância", + "settingsSpeedUnit": "Velocidade", + "reportTitle": "Relatórios", + "reportDevice": "Dispositivo", + "reportFrom": "De", + "reportTo": "Para", + "reportShow": "Mostrar", + "reportClear": "Limpar", + "positionFixTime": "Tempo", + "positionValid": "Válido", + "positionLatitude": "Latitude", + "positionLongitude": "Longitude", + "positionAltitude": "Altitude", + "positionSpeed": "Velocidade", + "positionCourse": "Curso", + "positionAddress": "Endereço", + "positionProtocol": "protocolo", + "serverTitle": "Configurações do Servidor", + "serverZoom": "Zoom", + "serverRegistration": "Registro", + "mapTitle": "Mapa", + "mapLayer": "Camada Mapa", + "mapCustom": "Mapa personalizado", + "mapOsm": "Open Street Mapa", + "mapBingKey": "Bing Maps Key", + "mapBingRoad": "Bing Mapas Estrada", + "mapBingAerial": "Bing Mapas Aérea", + "stateTitle": "Estado", + "stateName": "Parâmetro", + "stateValue": "Valor", + "commandTitle": "Comando", + "commandSend": "Enviar", + "commandType": "Tipo", + "commandSent": "Comando foi enviado", + "commandPositionPeriodic": "Posição Tempo", + "commandPositionStop": "Parar Posição", + "commandEngineStop": "Bloqueio Veículo", + "commandEngineResume": "Desbloqueio Veículo", + "commandFrequency": "Frequência", + "commandUnit": "Unidade" +}
\ No newline at end of file diff --git a/web/l10n/pt_BR.json b/web/l10n/pt_BR.json new file mode 100644 index 000000000..b1dabd737 --- /dev/null +++ b/web/l10n/pt_BR.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Carregando...", + "sharedSave": "Gravar", + "sharedCancel": "Cancelar", + "sharedAdd": "Adicionar", + "sharedEdit": "Editar", + "sharedRemove": "Remover", + "sharedRemoveConfirm": "Remover item?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "Hora", + "sharedMinute": "Minuto", + "sharedSecond": "Segundo", + "errorTitle": "Erro", + "errorUnknown": "Erro desconhecido", + "errorConnection": "Erro de conexão", + "userName": "Nome", + "userEmail": "Email", + "userPassword": "Senha", + "userAdmin": "Admin", + "loginTitle": "Entrar", + "loginLanguage": "Idioma", + "loginRegister": "Registrar", + "loginLogin": "Entrar", + "loginFailed": "Endereço de email ou senha incorretos", + "loginCreated": "O novo usuário foi registrado", + "loginLogout": "Sair", + "deviceDialog": "Dispositivo", + "deviceTitle": "Dispositivos", + "deviceName": "Nome", + "deviceIdentifier": "Identificador", + "deviceCommand": "Comando", + "settingsTitle": "Configurações", + "settingsUser": "Conta", + "settingsServer": "Servidor", + "settingsUsers": "Usuários", + "settingsDistanceUnit": "Distância", + "settingsSpeedUnit": "Velocidade", + "reportTitle": "Relatórios", + "reportDevice": "Dispositivo", + "reportFrom": "De", + "reportTo": "Para", + "reportShow": "Mostrar", + "reportClear": "Limpar", + "positionFixTime": "Tempo", + "positionValid": "Válido", + "positionLatitude": "Latitude", + "positionLongitude": "Longitude", + "positionAltitude": "Altitude", + "positionSpeed": "Velocidade", + "positionCourse": "Curso", + "positionAddress": "Endereço", + "positionProtocol": "Protocolo", + "serverTitle": "Configurações do Servidor", + "serverZoom": "Zoom", + "serverRegistration": "Registro", + "mapTitle": "Mapa", + "mapLayer": "Camada de Mapa", + "mapCustom": "Mapa Personalizado", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps Key", + "mapBingRoad": "Bing Maps Estradas", + "mapBingAerial": "Bing Maps Aéreo", + "stateTitle": "Estado", + "stateName": "Atributo", + "stateValue": "Valor", + "commandTitle": "Comando", + "commandSend": "Enviar", + "commandType": "Tipo", + "commandSent": "Comando foi enviado", + "commandPositionPeriodic": "Atualização Periódica", + "commandPositionStop": "Parar Atualizaçao", + "commandEngineStop": "Desligar Motor", + "commandEngineResume": "Religar Motor", + "commandFrequency": "Frequencia", + "commandUnit": "Unidade" +}
\ No newline at end of file diff --git a/web/l10n/ru.js b/web/l10n/ru.js deleted file mode 100644 index ea98d31ff..000000000 --- a/web/l10n/ru.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: 'Загрузка...', - sharedSave: 'Сохранить', - sharedCancel: 'Отмена', - sharedAdd: 'Добавить', - sharedEdit: 'Редактировать', - sharedRemove: 'Удалить', - sharedRemoveConfirm: 'Удалить элемент?', - sharedKm: 'км', - sharedMi: 'мили', - sharedKmh: 'км/ч', - sharedMph: 'миль/ч', - sharedHour: 'Часы', - sharedMinute: 'Минуты', - sharedSecond: 'Секунды', - - errorTitle: 'Ошибка', - errorUnknown: 'Неизвестная ошибка', - - userName: 'Имя', - userEmail: 'Email', - userPassword: 'Пароль', - userAdmin: 'Администратор', - - loginTitle: 'Вход', - loginLanguage: 'Язык', - loginRegister: 'Регистрация', - loginLogin: 'Вход', - loginFailed: 'Неправильный email адрес или пароль', - loginCreated: 'Новый пользователь зарегистрирован', - loginLogout: 'Выход', - - deviceDialog: 'Устройство', - deviceTitle: 'Устройства', - deviceName: 'Название', - deviceIdentifier: 'Идентификатор', - deviceCommand: 'Команда', - - settingsTitle: 'Настройки', - settingsUser: 'Аккаунт', - settingsServer: 'Сервер', - settingsUsers: 'Пользователи', - settingsDistanceUnit: 'Расстояние', - settingsSpeedUnit: 'Скорость', - - reportTitle: 'Отчеты', - reportDevice: 'Устройство', - reportFrom: 'С', - reportTo: 'По', - reportShow: 'Показать', - reportClear: 'Очистить', - - positionTime: 'Время', - positionValid: 'Корректность', - positionLatitude: 'Широта', - positionLongitude: 'Долгота', - positionAltitude: 'Высота', - positionSpeed: 'Скорость', - positionCourse: 'Курс', - positionAddress: 'Адрес', - positionProtocol: 'Протокол', - - serverTitle: 'Настройки Сервера', - serverZoom: 'Приближение', - serverRegistration: 'Регистрация', - - mapTitle: 'Карта', - mapLayer: 'Слой Карты', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Maps Дороги', - mapBingAerial: 'Bing Maps Спутник', - - stateTitle: 'Состояние', - stateName: 'Параметр', - stateValue: 'Значение', - - commandTitle: 'Команда', - commandSend: 'Отправить', - commandType: 'Тип', - commandPositionPeriodic: 'Начать Отслеживание', - commandPositionStop: 'Отменить Отслеживание', - commandEngineStop: 'Заблокировать Двигатель', - commandEngineResume: 'Разблокировать Двигатель', - commandFrequency: 'Частота', - commandUnit: 'Единицы' -}; diff --git a/web/l10n/ru.json b/web/l10n/ru.json new file mode 100644 index 000000000..7be75e55a --- /dev/null +++ b/web/l10n/ru.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Загрузка...", + "sharedSave": "Сохранить", + "sharedCancel": "Отмена", + "sharedAdd": "Добавить", + "sharedEdit": "Редактировать", + "sharedRemove": "Удалить", + "sharedRemoveConfirm": "Удалить элемент?", + "sharedKm": "км", + "sharedMi": "мили", + "sharedKmh": "км/ч", + "sharedMph": "миль/ч", + "sharedHour": "Часы", + "sharedMinute": "Минуты", + "sharedSecond": "Секунды", + "errorTitle": "Ошибка", + "errorUnknown": "Неизвестная ошибка", + "errorConnection": "Ошибка соединения", + "userName": "Имя", + "userEmail": "Email", + "userPassword": "Пароль", + "userAdmin": "Администратор", + "loginTitle": "Вход", + "loginLanguage": "Язык", + "loginRegister": "Регистрация", + "loginLogin": "Вход", + "loginFailed": "Неправильный email адрес или пароль", + "loginCreated": "Новый пользователь зарегистрирован", + "loginLogout": "Выход", + "deviceDialog": "Устройство", + "deviceTitle": "Устройства", + "deviceName": "Название", + "deviceIdentifier": "Идентификатор", + "deviceCommand": "Команда", + "settingsTitle": "Настройки", + "settingsUser": "Аккаунт", + "settingsServer": "Сервер", + "settingsUsers": "Пользователи", + "settingsDistanceUnit": "Расстояние", + "settingsSpeedUnit": "Скорость", + "reportTitle": "Отчеты", + "reportDevice": "Устройство", + "reportFrom": "С", + "reportTo": "По", + "reportShow": "Показать", + "reportClear": "Очистить", + "positionFixTime": "Время", + "positionValid": "Корректность", + "positionLatitude": "Широта", + "positionLongitude": "Долгота", + "positionAltitude": "Высота", + "positionSpeed": "Скорость", + "positionCourse": "Курс", + "positionAddress": "Адрес", + "positionProtocol": "Протокол", + "serverTitle": "Настройки Сервера", + "serverZoom": "Приближение", + "serverRegistration": "Регистрация", + "mapTitle": "Карта", + "mapLayer": "Слой Карты", + "mapCustom": "Пользовательская карта", + "mapOsm": "Open Street Map", + "mapBingKey": "Ключ Bing Maps", + "mapBingRoad": "Bing Maps Дороги", + "mapBingAerial": "Bing Maps Спутник", + "stateTitle": "Состояние", + "stateName": "Параметр", + "stateValue": "Значение", + "commandTitle": "Команда", + "commandSend": "Отправить", + "commandType": "Тип", + "commandSent": "Команда отправлена", + "commandPositionPeriodic": "Начать Отслеживание", + "commandPositionStop": "Отменить Отслеживание", + "commandEngineStop": "Заблокировать Двигатель", + "commandEngineResume": "Разблокировать Двигатель", + "commandFrequency": "Частота", + "commandUnit": "Единицы" +}
\ No newline at end of file diff --git a/web/l10n/si.js b/web/l10n/si.js deleted file mode 100755 index 649b81f4c..000000000 --- a/web/l10n/si.js +++ /dev/null @@ -1,88 +0,0 @@ -var Strings = { - sharedLoading: 'පූරණය ...', - sharedSave: 'සුරකින්න', - sharedCancel: 'අවලංගු කරන්න', - sharedAdd: 'එක් කරන්න', - sharedEdit: 'සංස්කරණය කරන්න', - sharedRemove: 'ඉවත් කරන්න', - sharedRemoveConfirm: 'අයිතමය ඉවත් කරන්න ද?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'පැය', - sharedMinute: 'මිනිත්තු', - sharedSecond: 'තත්පර', - - errorTitle: 'දෝෂයක්', - errorUnknown: 'නොදන්නා දෝෂයක්', - - userName: 'නම', - userEmail: 'විද්යුත් තැපෑල', - userPassword: 'මුරපදය', - userAdmin: 'පරිපාලක', - - loginTitle: 'පිවිසුම', - loginLanguage: 'භාෂාව', - loginRegister: 'ලියාපදිංචි කරන්න', - loginLogin: 'පිවිසුම', - loginFailed: 'ඊ-මේල් ලිපිනය හෝ මුරපදය වැරදිය', - loginCreated: 'නව පරිශීලක ලියාපදිංචි කරන ලදි ', - loginLogout: 'ඉවත්වන්න', - - deviceDialog: 'උපාංගය', - deviceTitle: 'උපාංග', - deviceName: 'නම', - deviceIdentifier: 'හඳුනාගැනීමේ කේතය', - deviceCommand: 'විධානය', - - settingsTitle: 'සැකසුම්', - settingsUser: 'ගිණුම', - settingsServer: 'සේවාදායකය', - settingsUsers: 'පරිශීලකයන්', - settingsDistanceUnit: 'දුර', - settingsSpeedUnit: 'වේගය', - - reportTitle: 'වාර්තා', - reportDevice: 'උපාංගය', - reportFrom: 'සිට', - reportTo: 'දක්වා', - reportShow: 'පෙන්වන්න', - reportClear: 'ඉවත් කරන්න', - - positionTime: 'කාලය', - positionValid: 'වලංගු', - positionLatitude: 'අක්ෂාංශ', - positionLongitude: 'දේශාංශ', - positionAltitude: 'උන්නතාංශය', - positionSpeed: 'වේගය', - positionCourse: 'දිගංශය', - positionAddress: 'ලිපිනය', - positionProtocol: 'ප්රොටොකෝලය', - - serverTitle: 'සේවාදායකයේ සැකසුම්', - serverZoom: 'විශාලනය', - serverRegistration: 'ලියාපදිංචි කිරීම', - - mapTitle: 'සිතියම', - mapLayer: 'සිතියම් ස්තරය', - mapCustom: 'අභිරුචි සිතියම', - mapOsm: 'Open Street Map', - mapBingKey: 'Bing Maps Key', - mapBingRoad: 'Bing Maps Road', - mapBingAerial: 'Bing Maps Aerial', - - stateTitle: 'තත්වය', - stateName: 'පරාමිතිය', - stateValue: 'අගය', - - commandTitle: 'විධානය', - commandSend: 'යවන්න', - commandType: 'වර්ගය', - commandPositionPeriodic: 'ආවර්තිතව වාර්තා කරන්න', - commandPositionStop: 'වාර්තා කිරීම නවත්වන්න', - commandEngineStop: 'එන්ජිම නවත්වන්න', - commandEngineResume: 'එන්ජිම නැවත ආරම්භ කරන්න', - commandFrequency: 'සංඛ්යාතය', - commandUnit: 'ඒකකය' -}; diff --git a/web/l10n/si.json b/web/l10n/si.json new file mode 100644 index 000000000..8e565423b --- /dev/null +++ b/web/l10n/si.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "පූරණය ...", + "sharedSave": "සුරකින්න", + "sharedCancel": "අවලංගු කරන්න", + "sharedAdd": "එක් කරන්න", + "sharedEdit": "සංස්කරණය කරන්න", + "sharedRemove": "ඉවත් කරන්න", + "sharedRemoveConfirm": "අයිතමය ඉවත් කරන්න ද?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "පැය", + "sharedMinute": "මිනිත්තු", + "sharedSecond": "තත්පර", + "errorTitle": "දෝෂයක්", + "errorUnknown": "නොදන්නා දෝෂයක්", + "errorConnection": "සම්බන්ධතා දෝෂයක්", + "userName": "නම", + "userEmail": "විද්යුත් තැපෑල", + "userPassword": "මුරපදය", + "userAdmin": "පරිපාලක", + "loginTitle": "පිවිසුම", + "loginLanguage": "භාෂාව", + "loginRegister": "ලියාපදිංචි කරන්න", + "loginLogin": "පිවිසුම", + "loginFailed": "ඊ-මේල් ලිපිනය හෝ මුරපදය වැරදිය", + "loginCreated": "නව පරිශීලක ලියාපදිංචි කරන ලදි", + "loginLogout": "ඉවත්වන්න", + "deviceDialog": "උපාංගය", + "deviceTitle": "උපාංග", + "deviceName": "නම", + "deviceIdentifier": "හඳුනාගැනීමේ කේතය", + "deviceCommand": "විධානය", + "settingsTitle": "සැකසුම්", + "settingsUser": "ගිණුම", + "settingsServer": "සේවාදායකය", + "settingsUsers": "පරිශීලකයන්", + "settingsDistanceUnit": "දුර", + "settingsSpeedUnit": "වේගය", + "reportTitle": "වාර්තා", + "reportDevice": "උපාංගය", + "reportFrom": "සිට", + "reportTo": "දක්වා", + "reportShow": "පෙන්වන්න", + "reportClear": "ඉවත් කරන්න", + "positionFixTime": "කාලය", + "positionValid": "වලංගු", + "positionLatitude": "අක්ෂාංශ", + "positionLongitude": "දේශාංශ", + "positionAltitude": "උන්නතාංශය", + "positionSpeed": "වේගය", + "positionCourse": "දිගංශය", + "positionAddress": "ලිපිනය", + "positionProtocol": "ප්රොටොකෝලය", + "serverTitle": "සේවාදායකයේ සැකසුම්", + "serverZoom": "විශාලනය", + "serverRegistration": "ලියාපදිංචි කිරීම", + "mapTitle": "සිතියම", + "mapLayer": "සිතියම් ස්තරය", + "mapCustom": "අභිරුචි සිතියම", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps Key", + "mapBingRoad": "Bing Maps Road", + "mapBingAerial": "Bing Maps Aerial", + "stateTitle": "තත්වය", + "stateName": "පරාමිතිය", + "stateValue": "අගය", + "commandTitle": "විධානය", + "commandSend": "යවන්න", + "commandType": "වර්ගය", + "commandSent": "අණ යවා ඇත", + "commandPositionPeriodic": "ආවර්තිතව වාර්තා කරන්න", + "commandPositionStop": "වාර්තා කිරීම නවත්වන්න", + "commandEngineStop": "එන්ජිම නවත්වන්න", + "commandEngineResume": "එන්ජිම නැවත ආරම්භ කරන්න", + "commandFrequency": "සංඛ්යාතය", + "commandUnit": "ඒකකය" +}
\ No newline at end of file diff --git a/web/l10n/sk.js b/web/l10n/sk.js deleted file mode 100644 index 98d131b65..000000000 --- a/web/l10n/sk.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: 'Načítava...', - sharedSave: 'Uloženie', - sharedCancel: 'Zrušenie', - sharedAdd: 'Pridať', - sharedEdit: 'Úprava', - sharedRemove: 'Odstrániť', - sharedRemoveConfirm: 'Odstrániť položku?', - sharedKm: 'Km', - sharedMi: 'mi', - sharedKmh: 'Km/h', - sharedMph: 'mph', - sharedHour: 'Hodina', - sharedMinute: 'Minúta', - sharedSecond: 'Druhý', - - errorTitle: 'Chyba', - errorUnknown: 'Neznáma chyba', - - userName: 'Meno', - userEmail: 'E-mail', - userPassword: 'Heslo', - userAdmin: 'Admin', - - loginTitle: 'Prihlásenie', - loginLanguage: 'Jazyk', - loginRegister: 'Registrovať', - loginLogin: 'Prihlásenie', - loginFailed: 'Nesprávna e-mailová adresa alebo heslo', - loginCreated: 'Nový užívateľ sa zaregistroval', - loginLogout: 'Odhlásiť', - - deviceDialog: 'Zariadenie', - deviceTitle: 'Zariadena', - deviceName: 'Meno', - deviceIdentifier: 'Identifikátor', - deviceCommand: 'Príkaz', - - settingsTitle: 'Nastavenia', - settingsUser: 'Účet', - settingsServer: 'Server', - settingsUsers: 'Užívatelia', - settingsDistanceUnit: 'Vzdialenosť', - settingsSpeedUnit: 'Rýchlosť jazdy', - - reportTitle: 'Správy', - reportDevice: 'Zariadenie', - reportFrom: 'Z', - reportTo: 'do', - reportShow: 'Zobraziť', - reportClear: 'Vyčistiť', - - positionTime: 'Čas', - positionValid: 'Platný', - positionLatitude: 'Šírka', - positionLongitude: 'Dĺžka', - positionAltitude: 'Výška', - positionSpeed: 'Rýchlosť jazdy', - positionCourse: 'Kurz', - positionAddress: 'Adresa', - positionProtocol: 'Protokol', - - serverTitle: 'Nastavenie servera', - serverZoom: 'Zoom', - serverRegistration: 'Registrácia', - - mapTitle: 'Mapa', - mapLayer: 'Mapové vrstvy', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Maps Road', - mapBingAerial: 'Bing Maps Arial', - - stateTitle: 'Štát', - stateName: 'Parameter', - stateValue: 'Hodnota', - - commandTitle: 'Príkaz', - commandSend: 'Odoslať', - commandType: 'Typ', - commandPositionPeriodic: 'Pravidelné podávanie správ', - commandPositionStop: 'Zastavte podávanie správ', - commandEngineStop: 'Zastavenie motora', - commandEngineResume: 'Spustenie motora', - commandFrequency: 'Frekvencia', - commandUnit: 'Unit' -}; diff --git a/web/l10n/sk.json b/web/l10n/sk.json new file mode 100644 index 000000000..52044643c --- /dev/null +++ b/web/l10n/sk.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Načítava...", + "sharedSave": "Uloženie", + "sharedCancel": "Zrušenie", + "sharedAdd": "Pridať", + "sharedEdit": "Úprava", + "sharedRemove": "Odstrániť", + "sharedRemoveConfirm": "Odstrániť položku?", + "sharedKm": "Km", + "sharedMi": "mi", + "sharedKmh": "Km/h", + "sharedMph": "mph", + "sharedHour": "Hodina", + "sharedMinute": "Minúta", + "sharedSecond": "Druhý", + "errorTitle": "Chyba", + "errorUnknown": "Neznáma chyba", + "errorConnection": "Chyba pripojenia", + "userName": "Meno", + "userEmail": "E-mail", + "userPassword": "Heslo", + "userAdmin": "Admin", + "loginTitle": "Prihlásenie", + "loginLanguage": "Jazyk", + "loginRegister": "Registrovať", + "loginLogin": "Prihlásenie", + "loginFailed": "Nesprávna e-mailová adresa alebo heslo", + "loginCreated": "Nový užívateľ sa zaregistroval", + "loginLogout": "Odhlásiť", + "deviceDialog": "Zariadenie", + "deviceTitle": "Zariadena", + "deviceName": "Meno", + "deviceIdentifier": "Identifikátor", + "deviceCommand": "Príkaz", + "settingsTitle": "Nastavenia", + "settingsUser": "Účet", + "settingsServer": "Server", + "settingsUsers": "Užívatelia", + "settingsDistanceUnit": "Vzdialenosť", + "settingsSpeedUnit": "Rýchlosť jazdy", + "reportTitle": "Správy", + "reportDevice": "Zariadenie", + "reportFrom": "Od", + "reportTo": "Do", + "reportShow": "Zobraziť", + "reportClear": "Vyčistiť", + "positionFixTime": "Čas", + "positionValid": "Platný", + "positionLatitude": "Šírka", + "positionLongitude": "Dĺžka", + "positionAltitude": "Výška", + "positionSpeed": "Rýchlosť jazdy", + "positionCourse": "Kurz", + "positionAddress": "Adresa", + "positionProtocol": "Protokol", + "serverTitle": "Nastavenie servera", + "serverZoom": "Zoom", + "serverRegistration": "Registrácia", + "mapTitle": "Mapa", + "mapLayer": "Mapové vrstvy", + "mapCustom": "Vlastná mapa", + "mapOsm": "Open Street Map", + "mapBingKey": "Klúč Bing Maps", + "mapBingRoad": "Bing Maps Road", + "mapBingAerial": "Bing Maps Arial", + "stateTitle": "Štát", + "stateName": "Parameter", + "stateValue": "Hodnota", + "commandTitle": "Príkaz", + "commandSend": "Odoslať", + "commandType": "Typ", + "commandSent": "Príkaz bol odoslaný", + "commandPositionPeriodic": "Pravidelné podávanie správ", + "commandPositionStop": "Zastavte podávanie správ", + "commandEngineStop": "Zastavenie motora", + "commandEngineResume": "Spustenie motora", + "commandFrequency": "Frekvencia", + "commandUnit": "Unit" +}
\ No newline at end of file diff --git a/web/l10n/sl.js b/web/l10n/sl.js deleted file mode 100644 index df8c8ab18..000000000 --- a/web/l10n/sl.js +++ /dev/null @@ -1,86 +0,0 @@ -var strings = { - sharedLoading: 'Nalagam...', - sharedSave: 'Shrani', - sharedCancel: 'Prekini', - sharedAdd: 'Dodaj', - sharedEdit: 'Uredi', - sharedRemove: 'Odstrani', - sharedRemoveConfirm: 'Odstranim zapis?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'Ura', - sharedMinute: 'Minuta', - sharedSecond: 'Sekunda', - - errorTitle: 'Napaka', - errorUnknown: 'Neznana napaka', - - userName: 'Ime', - userEmail: 'E-Pošta', - userPassword: 'Geslo', - userAdmin: 'Admin', - - loginTitle: 'Prijava', - loginLanguage: 'Jezik', - loginRegister: 'Registracija', - loginLogin: 'Prijava', - loginFailed: 'Nepravilna e-pošta ali geslo', - loginCreated: 'Nov uporabnik je registriran', - loginLogout: 'Odjava', - - deviceDialog: 'Naprave', - deviceTitle: 'Naprave', - deviceName: 'Naziv', - deviceIdentifier: 'Identifikacija', - deviceCommand: 'Ukaz', - - settingsTitle: 'Nastavitve', - settingsUser: 'Račun', - settingsServer: 'Strežnik', - settingsUsers: 'Uporabniki', - settingsDistanceUnit: 'Razdalja', - settingsSpeedUnit: 'Hitrost', - - reportTitle: 'Poročila', - reportDevice: 'Naprava', - reportFrom: 'Od', - reportTo: 'Do', - reportShow: 'Prikaži', - reportClear: 'Očisti', - - positionTime: 'Čas', - positionValid: 'Veljavnost', - positionLatitude: 'Širina', - positionLongitude: 'Dolžina', - positionAltitude: 'Višina', - positionSpeed: 'Hitrost', - positionCourse: 'Smer', - positionAddress: 'Naslov', - positionProtocol: 'Protokol', - - serverTitle: 'Nastavitve strežnika', - serverZoom: 'Povečava', - serverRegistration: 'Registracija', - - mapTitle: 'Karta', - mapLayer: 'Zemljevidi', - mapOsm: 'Open Street Karta', - mapBingRoad: 'Bing Maps Ceste', - mapBingAerial: 'Bing Maps Satelit', - - stateTitle: 'Stanje', - stateName: 'Parameter', - stateValue: 'Vrednost', - - commandTitle: 'Ukaz', - commandSend: 'Pošlji', - commandType: 'Tip', - commandPositionPeriodic: 'Periodično poročanje', - commandPositionStop: 'Ustavi poročanje', - commandEngineStop: 'Ugasni motor', - commandEngineResume: 'Prižgi motor', - commandFrequency: 'Frekvenca', - commandUnit: 'Naprava' -}; diff --git a/web/l10n/sl.json b/web/l10n/sl.json new file mode 100644 index 000000000..6af46c702 --- /dev/null +++ b/web/l10n/sl.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Nalagam...", + "sharedSave": "Shrani", + "sharedCancel": "Prekini", + "sharedAdd": "Dodaj", + "sharedEdit": "Uredi", + "sharedRemove": "Odstrani", + "sharedRemoveConfirm": "Odstranim zapis?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "Ura", + "sharedMinute": "Minuta", + "sharedSecond": "Sekunda", + "errorTitle": "Napaka", + "errorUnknown": "Neznana napaka", + "errorConnection": "Napaka v povezavi", + "userName": "Ime", + "userEmail": "E-Pošta", + "userPassword": "Geslo", + "userAdmin": "Admin", + "loginTitle": "Prijava", + "loginLanguage": "Jezik", + "loginRegister": "Registracija", + "loginLogin": "Prijava", + "loginFailed": "Nepravilna e-pošta ali geslo", + "loginCreated": "Nov uporabnik je registriran", + "loginLogout": "Odjava", + "deviceDialog": "Naprave", + "deviceTitle": "Naprave", + "deviceName": "Naziv", + "deviceIdentifier": "Identifikacija", + "deviceCommand": "Ukaz", + "settingsTitle": "Nastavitve", + "settingsUser": "Račun", + "settingsServer": "Strežnik", + "settingsUsers": "Uporabniki", + "settingsDistanceUnit": "Razdalja", + "settingsSpeedUnit": "Hitrost", + "reportTitle": "Poročila", + "reportDevice": "Naprava", + "reportFrom": "Od", + "reportTo": "Do", + "reportShow": "Prikaži", + "reportClear": "Očisti", + "positionFixTime": "Čas", + "positionValid": "Veljavnost", + "positionLatitude": "Širina", + "positionLongitude": "Dolžina", + "positionAltitude": "Višina", + "positionSpeed": "Hitrost", + "positionCourse": "Smer", + "positionAddress": "Naslov", + "positionProtocol": "Protokol", + "serverTitle": "Nastavitve strežnika", + "serverZoom": "Povečava", + "serverRegistration": "Registracija", + "mapTitle": "Karta", + "mapLayer": "Zemljevidi", + "mapCustom": "Poljubna karta", + "mapOsm": "Open Street Karta", + "mapBingKey": "Bing Mapk Ključ", + "mapBingRoad": "Bing Maps Ceste", + "mapBingAerial": "Bing Maps Satelit", + "stateTitle": "Stanje", + "stateName": "Parameter", + "stateValue": "Vrednost", + "commandTitle": "Ukaz", + "commandSend": "Pošlji", + "commandType": "Tip", + "commandSent": "Ukaz poslan", + "commandPositionPeriodic": "Periodično poročanje", + "commandPositionStop": "Ustavi poročanje", + "commandEngineStop": "Ugasni motor", + "commandEngineResume": "Prižgi motor", + "commandFrequency": "Frekvenca", + "commandUnit": "Naprava" +}
\ No newline at end of file diff --git a/web/l10n/sr.js b/web/l10n/sr.js deleted file mode 100644 index 3c1588401..000000000 --- a/web/l10n/sr.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: 'Učitava...', - sharedSave: 'Sačuvaj', - sharedCancel: 'Odustani', - sharedAdd: 'Dodaj', - sharedEdit: 'Podesi', - sharedRemove: 'Ukloni', - sharedRemoveConfirm: 'Ukloniti jedinicu?', - sharedKm: 'km', - sharedMi: 'mi', - sharedKmh: 'km/h', - sharedMph: 'mph', - sharedHour: 'Čas', - sharedMinute: 'Minut', - sharedSecond: 'Sekunda', - - errorTitle: 'Greška', - errorUnknown: 'Nepoznata greška', - - userName: 'Ime', - userEmail: 'Email', - userPassword: 'Lozinka', - userAdmin: 'Admin', - - loginTitle: 'Prijava', - loginLanguage: 'Jezik', - loginRegister: 'Registruj se', - loginLogin: 'Prijava', - loginFailed: 'Neispravna email adresa ili lozinka', - loginCreated: 'Novi korisnik je registrovan', - loginLogout: 'Odjava', - - deviceDialog: 'Uređaj', - deviceTitle: 'Uređaji', - deviceName: 'Ime', - deviceIdentifier: 'Identifikator', - deviceCommand: 'Komanda', - - settingsTitle: 'Podešavanja', - settingsUser: 'Nalog', - settingsServer: 'Server', - settingsUsers: 'Korisnici', - settingsDistanceUnit: 'Udaljenost', - settingsSpeedUnit: 'Brzina', - - reportTitle: 'Izveštaji', - reportDevice: 'Uređaj', - reportFrom: 'Od', - reportTo: 'Do', - reportShow: 'Prikaži', - reportClear: 'Izbriši', - - positionTime: 'Vreme', - positionValid: 'Ispravno', - positionLatitude: 'Geografska širina', - positionLongitude: 'Geografska dužina', - positionAltitude: 'Visina', - positionSpeed: 'Brzina', - positionCourse: 'Pravac', - positionAddress: 'Adresa', - positionProtocol: 'Protokol', - - serverTitle: 'Podešavanja Servera', - serverZoom: 'Zumiranje', - serverRegistration: 'Registracija', - - mapTitle: 'Mapa', - mapLayer: 'Vrsta Mape', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Maps Road', - mapBingAerial: 'Bing Maps Aerial', - - stateTitle: 'Stanje', - stateName: 'Parametar', - stateValue: 'Vrednost', - - commandTitle: 'Komanda', - commandSend: 'Pošalji', - commandType: 'Tip', - commandPositionPeriodic: 'Periodično izveštavanje', - commandPositionStop: 'Prekini izveštavanja', - commandEngineStop: 'Zaustavi motor', - commandEngineResume: 'Pokreni motor', - commandFrequency: 'Frekvencija', - commandUnit: 'Jedinica' -}; diff --git a/web/l10n/sr.json b/web/l10n/sr.json new file mode 100644 index 000000000..405ff933a --- /dev/null +++ b/web/l10n/sr.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Učitava...", + "sharedSave": "Sačuvaj", + "sharedCancel": "Odustani", + "sharedAdd": "Dodaj", + "sharedEdit": "Podesi", + "sharedRemove": "Ukloni", + "sharedRemoveConfirm": "Ukloniti jedinicu?", + "sharedKm": "km", + "sharedMi": "mi", + "sharedKmh": "km/h", + "sharedMph": "mph", + "sharedHour": "Čas", + "sharedMinute": "Minut", + "sharedSecond": "Sekunda", + "errorTitle": "Greška", + "errorUnknown": "Nepoznata greška", + "errorConnection": "Greška u konekciji", + "userName": "Ime", + "userEmail": "Email", + "userPassword": "Lozinka", + "userAdmin": "Admin", + "loginTitle": "Prijava", + "loginLanguage": "Jezik", + "loginRegister": "Registruj se", + "loginLogin": "Prijava", + "loginFailed": "Neispravna email adresa ili lozinka", + "loginCreated": "Novi korisnik je registrovan", + "loginLogout": "Odjava", + "deviceDialog": "Uređaj", + "deviceTitle": "Uređaji", + "deviceName": "Ime", + "deviceIdentifier": "Identifikator", + "deviceCommand": "Komanda", + "settingsTitle": "Podešavanja", + "settingsUser": "Nalog", + "settingsServer": "Server", + "settingsUsers": "Korisnici", + "settingsDistanceUnit": "Udaljenost", + "settingsSpeedUnit": "Brzina", + "reportTitle": "Izveštaji", + "reportDevice": "Uređaj", + "reportFrom": "Od", + "reportTo": "Do", + "reportShow": "Prikaži", + "reportClear": "Izbriši", + "positionFixTime": "Vreme", + "positionValid": "Ispravno", + "positionLatitude": "Geografska širina", + "positionLongitude": "Geografska dužina", + "positionAltitude": "Visina", + "positionSpeed": "Brzina", + "positionCourse": "Pravac", + "positionAddress": "Adresa", + "positionProtocol": "Protokol", + "serverTitle": "Podešavanja Servera", + "serverZoom": "Zumiranje", + "serverRegistration": "Registracija", + "mapTitle": "Mapa", + "mapLayer": "Vrsta Mape", + "mapCustom": "Prilagođena mapa", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps Key", + "mapBingRoad": "Bing Maps Road", + "mapBingAerial": "Bing Maps Aerial", + "stateTitle": "Stanje", + "stateName": "Parametar", + "stateValue": "Vrednost", + "commandTitle": "Komanda", + "commandSend": "Pošalji", + "commandType": "Tip", + "commandSent": "Komanda je poslata", + "commandPositionPeriodic": "Periodično izveštavanje", + "commandPositionStop": "Prekini izveštavanja", + "commandEngineStop": "Zaustavi motor", + "commandEngineResume": "Pokreni motor", + "commandFrequency": "Frekvencija", + "commandUnit": "Jedinica" +}
\ No newline at end of file diff --git a/web/l10n/th.js b/web/l10n/th.js deleted file mode 100644 index bc0129353..000000000 --- a/web/l10n/th.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: 'โหลด', - sharedSave: 'เก็บ (แฟ้มข้อมูล)', - sharedCancel: 'ยกเลิก', - sharedAdd: 'เพิ่ม', - sharedEdit: 'ตรวจแก้ ปรับเปลี่ยนข้อมูล', - sharedRemove: 'ย้ายออก', - sharedRemoveConfirm: 'ลบรายการ', - sharedKm: 'กม.', - sharedMi: 'ไมล์', - sharedKmh: 'กม. / ชม', - sharedMph: 'ไมล์ต่อชั่วโมง', - sharedHour: 'ชั่วโมง', - sharedMinute: 'นาที', - sharedSecond: 'วินาที', - - errorTitle: 'ผิดพลาด', - errorUnknown: 'ข้อผิดพลาดที่ไม่รู้จัก', - - userName: 'ชื่อ', - userEmail: 'อีเมล', - userPassword: 'รหัสผ่าน', - userAdmin: 'ผู้ดูแลระบบ', - - loginTitle: 'เข้าสู่ระบบ', - loginLanguage: 'ภาษา', - loginRegister: 'ลงทะเบียน', - loginLogin: 'เข้าสู่ระบบ', - loginFailed: 'ที่อยู่อีเมลหรือรหัสผ่านไม่ถูกต้อง', - loginCreated: 'ผู้ใช้ใหม่ ได้รับการจดทะเบียน', - loginLogout: 'ออกจากระบบ', - - deviceDialog: 'เครื่อง/อุปกรณ์', - deviceTitle: 'เครื่อง/อุปกรณ์', - deviceName: 'ชื่อ', - deviceIdentifier: 'ระบุ', - deviceCommand: 'คำสั่ง', - - settingsTitle: 'การตั้งค่า', - settingsUser: 'บัญชี', - settingsServer: 'ผู้ให้บริการ', - settingsUsers: 'ผู้ใช้งาน', - settingsDistanceUnit: 'ระยะทาง', - settingsSpeedUnit: 'ความเร็ว', - - reportTitle: 'รายงาน', - reportDevice: 'เครื่อง/อุปกรณ์', - reportFrom: 'จาก', - reportTo: 'ไปถึง', - reportShow: 'แสดง', - reportClear: 'ขจัด', - - positionTime: 'เวลา', - positionValid: 'ถูกต้อง', - positionLatitude: 'ละติจูด', - positionLongitude: 'ลองจิจูด', - positionAltitude: 'ระดับความสูง', - positionSpeed: 'ความเร็ว', - positionCourse: 'แนวทางเดิน', - positionAddress: 'ที่อยู่', - positionProtocol: 'โปรโตคอล', - - serverTitle: 'การตั้งค่าเซิร์ฟเวอ', - serverZoom: 'เลื่อนใกล้/ไกล', - serverRegistration: 'ลงทะเบียน', - - mapTitle: 'แผนที่', - mapLayer: 'ชั้น แผนที่', - mapOsm: 'Open Street Map', - mapBingRoad: 'Bing Maps ถนน', - mapBingAerial: 'Bing Maps อากาศ', - - stateTitle: 'สถานะ', - stateName: 'พารามิเตอร์', - stateValue: 'มูลค่า', - - commandTitle: 'คำสั่ง', - commandSend: 'ส่ง', - commandType: 'ชนิด', - commandPositionPeriodic: 'แก้ไขตำแหน่ง', - commandPositionStop: 'ตำแหน่ง หยุด', - commandEngineStop: 'หยุดเครื่องยนต์', - commandEngineResume: 'เริ่มครื่องยนต์ใหม่', - commandFrequency: 'ความถี่', - commandUnit: 'หน่วย' -}; diff --git a/web/l10n/th.json b/web/l10n/th.json new file mode 100644 index 000000000..bb93bab4e --- /dev/null +++ b/web/l10n/th.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "โหลด", + "sharedSave": "เก็บ (แฟ้มข้อมูล)", + "sharedCancel": "ยกเลิก", + "sharedAdd": "เพิ่ม", + "sharedEdit": "ตรวจแก้ ปรับเปลี่ยนข้อมูล", + "sharedRemove": "ย้ายออก", + "sharedRemoveConfirm": "ลบรายการ", + "sharedKm": "กม.", + "sharedMi": "ไมล์", + "sharedKmh": "กม. / ชม", + "sharedMph": "ไมล์ต่อชั่วโมง", + "sharedHour": "ชั่วโมง", + "sharedMinute": "นาที", + "sharedSecond": "วินาที", + "errorTitle": "ผิดพลาด", + "errorUnknown": "ข้อผิดพลาดที่ไม่รู้จัก", + "errorConnection": "การเชื่อมต่อผิดพลาด", + "userName": "ชื่อ", + "userEmail": "อีเมล", + "userPassword": "รหัสผ่าน", + "userAdmin": "ผู้ดูแลระบบ", + "loginTitle": "เข้าสู่ระบบ", + "loginLanguage": "ภาษา", + "loginRegister": "ลงทะเบียน", + "loginLogin": "เข้าสู่ระบบ", + "loginFailed": "ที่อยู่อีเมลหรือรหัสผ่านไม่ถูกต้อง", + "loginCreated": "ผู้ใช้ใหม่ ได้รับการจดทะเบียน", + "loginLogout": "ออกจากระบบ", + "deviceDialog": "เครื่อง/อุปกรณ์", + "deviceTitle": "เครื่อง/อุปกรณ์", + "deviceName": "ชื่อ", + "deviceIdentifier": "ระบุ", + "deviceCommand": "คำสั่ง", + "settingsTitle": "การตั้งค่า", + "settingsUser": "บัญชี", + "settingsServer": "ผู้ให้บริการ", + "settingsUsers": "ผู้ใช้งาน", + "settingsDistanceUnit": "ระยะทาง", + "settingsSpeedUnit": "ความเร็ว", + "reportTitle": "รายงาน", + "reportDevice": "เครื่อง/อุปกรณ์", + "reportFrom": "จาก", + "reportTo": "ไปถึง", + "reportShow": "แสดง", + "reportClear": "ขจัด", + "positionFixTime": "เวลา", + "positionValid": "ถูกต้อง", + "positionLatitude": "ละติจูด", + "positionLongitude": "ลองจิจูด", + "positionAltitude": "ระดับความสูง", + "positionSpeed": "ความเร็ว", + "positionCourse": "แนวทางเดิน", + "positionAddress": "ที่อยู่", + "positionProtocol": "โปรโตคอล", + "serverTitle": "การตั้งค่าเซิร์ฟเวอ", + "serverZoom": "เลื่อนใกล้/ไกล", + "serverRegistration": "ลงทะเบียน", + "mapTitle": "แผนที่", + "mapLayer": "ชั้น แผนที่", + "mapCustom": "แผนที่ที่กำหนดเอง", + "mapOsm": "Open Street Map", + "mapBingKey": "Bing Maps สำคัญ", + "mapBingRoad": "Bing Maps ถนน", + "mapBingAerial": "Bing Maps อากาศ", + "stateTitle": "สถานะ", + "stateName": "พารามิเตอร์", + "stateValue": "มูลค่า", + "commandTitle": "คำสั่ง", + "commandSend": "ส่ง", + "commandType": "ชนิด", + "commandSent": "คำสั่งถูกส่งไปแล้ว", + "commandPositionPeriodic": "แก้ไขตำแหน่ง", + "commandPositionStop": "ตำแหน่ง หยุด", + "commandEngineStop": "หยุดเครื่องยนต์", + "commandEngineResume": "เริ่มครื่องยนต์ใหม่", + "commandFrequency": "ความถี่", + "commandUnit": "หน่วย" +}
\ No newline at end of file diff --git a/web/l10n/uk.json b/web/l10n/uk.json new file mode 100644 index 000000000..df9fb3620 --- /dev/null +++ b/web/l10n/uk.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "Завантаження... ", + "sharedSave": "Зберегти", + "sharedCancel": "Відміна", + "sharedAdd": "Додати", + "sharedEdit": "Редагувати", + "sharedRemove": "Видалити", + "sharedRemoveConfirm": "Видалити пункт?", + "sharedKm": "км", + "sharedMi": "Милi", + "sharedKmh": "км/год", + "sharedMph": "Миль/год", + "sharedHour": "Години", + "sharedMinute": "Хвилини", + "sharedSecond": "Секунди", + "errorTitle": "Помилка", + "errorUnknown": "Невiдома помилка", + "errorConnection": "Помилка з'єднання", + "userName": "Iм'я", + "userEmail": "E-mail", + "userPassword": "Пароль", + "userAdmin": "Адмiнiстратор", + "loginTitle": "Логiн", + "loginLanguage": "Мова", + "loginRegister": "Реєстрація", + "loginLogin": "Ввійти", + "loginFailed": "Неправильне адреса електронної пошти або пароль", + "loginCreated": "Новий користувач був зареєстрований", + "loginLogout": "Вийти", + "deviceDialog": "Пристрій", + "deviceTitle": " Прилади", + "deviceName": "Iм'я ", + "deviceIdentifier": "Iдентифікатор", + "deviceCommand": "Команда", + "settingsTitle": "Налаштування", + "settingsUser": "Аккаунт", + "settingsServer": "Сервер", + "settingsUsers": "Користувач", + "settingsDistanceUnit": "Відстань", + "settingsSpeedUnit": "Швидкість", + "reportTitle": "Звіти", + "reportDevice": "Пристрій ", + "reportFrom": "З", + "reportTo": "До", + "reportShow": "Показати", + "reportClear": "Очистити", + "positionFixTime": "Час ", + "positionValid": "Дійсний", + "positionLatitude": "Широта", + "positionLongitude": "Довгота ", + "positionAltitude": "Висота", + "positionSpeed": "Швидкість ", + "positionCourse": "Курс", + "positionAddress": "Адреса", + "positionProtocol": "Протокол", + "serverTitle": "Налаштування сервера", + "serverZoom": "Наближення", + "serverRegistration": "Реєстрація", + "mapTitle": "Карта", + "mapLayer": "Шар карти", + "mapCustom": "Користувальницька карта", + "mapOsm": "Open Street Map", + "mapBingKey": "Ключ Bing Maps ", + "mapBingRoad": "Bing Maps Дороги", + "mapBingAerial": "Bing Maps Супутник", + "stateTitle": "Стан", + "stateName": "Атрибут", + "stateValue": "Значення ", + "commandTitle": "Команда ", + "commandSend": "Послати. ", + "commandType": "Тип", + "commandSent": "Команда була відправлена", + "commandPositionPeriodic": "Періодична звітність", + "commandPositionStop": "Скасувати відстеження. ", + "commandEngineStop": "Заблокувати двигун ", + "commandEngineResume": "Розблокувати двигун", + "commandFrequency": "Частота", + "commandUnit": "Одиниці" +}
\ No newline at end of file diff --git a/web/l10n/zh.js b/web/l10n/zh.js deleted file mode 100644 index 01c6bec47..000000000 --- a/web/l10n/zh.js +++ /dev/null @@ -1,86 +0,0 @@ -var Strings = { - sharedLoading: '加载', - sharedSave: '保存', - sharedCancel: '取消', - sharedAdd: '新建', - sharedEdit: '编辑', - sharedRemove: '移除', - sharedRemoveConfirm: '要移除选项吗?', - sharedKm: '千米', - sharedMi: '海里', - sharedKmh: '千米/小时', - sharedMph: '每小时英里数', - sharedHour: '小时', - sharedMinute: '分钟', - sharedSecond: '秒', - - errorTitle: '错误', - errorUnknown: '未知错误', - - userName: '名字', - userEmail: '邮箱', - userPassword: '密码', - userAdmin: '管理员', - - loginTitle: '登录', - loginLanguage: '语言', - loginRegister: '注册', - loginLogin: '登录', - loginFailed: '邮箱地址或密码不对', - loginCreated: '新用户已经被注册了', - loginLogout: '登出', - - deviceDialog: '设备', - deviceTitle: '设备', - deviceName: '名字', - deviceIdentifier: '标识符', - deviceCommand: '指令', - - settingsTitle: '设置', - settingsUser: '账户', - settingsServer: '服务器', - settingsUsers: '用户', - settingsDistanceUnit: '距离', - settingsSpeedUnit: '速度', - - reportTitle: '报表', - reportDevice: '设备', - reportFrom: '开始', - reportTo: '结束', - reportShow: '显示', - reportClear: '清空', - - positionTime: '时间', - positionValid: '有效', - positionLatitude: '纬度', - positionLongitude: '经度', - positionAltitude: '海拔', - positionSpeed: '速度', - positionCourse: '航向', - positionAddress: '地址', - positionProtocol: '协议', - - serverTitle: '服务器设置', - serverZoom: '缩放', - serverRegistration: '注册', - - mapTitle: '地图', - mapLayer: '地图图层', - mapOsm: 'OpenStreetMap 地图', - mapBingRoad: 'Bing 公路线路地图', - mapBingAerial: 'Bing 航测地图', - - stateTitle: '状态', - stateName: '参数', - stateValue: '数值', - - commandTitle: '命令', - commandSend: '发送', - commandType: '类型', - commandPositionPeriodic: '位置获取', - commandPositionStop: '位置停止', - commandEngineStop: '引擎熄火', - commandEngineResume: '引擎启动', - commandFrequency: '频率', - commandUnit: '单位' -}; diff --git a/web/l10n/zh.json b/web/l10n/zh.json new file mode 100644 index 000000000..15f77c270 --- /dev/null +++ b/web/l10n/zh.json @@ -0,0 +1,79 @@ +{ + "sharedLoading": "加载", + "sharedSave": "保存", + "sharedCancel": "取消", + "sharedAdd": "新建", + "sharedEdit": "编辑", + "sharedRemove": "移除", + "sharedRemoveConfirm": "要移除选项吗?", + "sharedKm": "千米", + "sharedMi": "海里", + "sharedKmh": "千米/小时", + "sharedMph": "每小时英里数", + "sharedHour": "小时", + "sharedMinute": "分钟", + "sharedSecond": "秒", + "errorTitle": "错误", + "errorUnknown": "未知错误", + "errorConnection": "连接错误", + "userName": "名字", + "userEmail": "邮箱", + "userPassword": "密码", + "userAdmin": "管理员", + "loginTitle": "登录", + "loginLanguage": "语言", + "loginRegister": "注册", + "loginLogin": "登录", + "loginFailed": "邮箱地址或密码不对", + "loginCreated": "新用户已经被注册了", + "loginLogout": "登出", + "deviceDialog": "设备", + "deviceTitle": "设备", + "deviceName": "名字", + "deviceIdentifier": "标识符", + "deviceCommand": "指令", + "settingsTitle": "设置", + "settingsUser": "账户", + "settingsServer": "服务器", + "settingsUsers": "用户", + "settingsDistanceUnit": "距离", + "settingsSpeedUnit": "速度", + "reportTitle": "报表", + "reportDevice": "设备", + "reportFrom": "开始", + "reportTo": "结束", + "reportShow": "显示", + "reportClear": "清空", + "positionFixTime": "时间", + "positionValid": "有效", + "positionLatitude": "纬度", + "positionLongitude": "经度", + "positionAltitude": "海拔", + "positionSpeed": "速度", + "positionCourse": "航向", + "positionAddress": "地址", + "positionProtocol": "协议", + "serverTitle": "服务器设置", + "serverZoom": "缩放", + "serverRegistration": "注册", + "mapTitle": "地图", + "mapLayer": "地图图层", + "mapCustom": "自定义地图", + "mapOsm": "OpenStreetMap 地图", + "mapBingKey": "Bing 旅游重点", + "mapBingRoad": "Bing 公路线路地图", + "mapBingAerial": "Bing 航测地图", + "stateTitle": "状态", + "stateName": "参数", + "stateValue": "数值", + "commandTitle": "命令", + "commandSend": "发送", + "commandType": "类型", + "commandSent": "命令已发送", + "commandPositionPeriodic": "位置获取", + "commandPositionStop": "位置停止", + "commandEngineStop": "引擎熄火", + "commandEngineResume": "引擎启动", + "commandFrequency": "频率", + "commandUnit": "单位" +}
\ No newline at end of file diff --git a/web/locale.js b/web/locale.js index ff07bf166..a5acb0ad3 100644 --- a/web/locale.js +++ b/web/locale.js @@ -21,10 +21,11 @@ Ext.Loader.setConfig({ }); Locale.languages = { + 'ar': { name: 'العربية', code: 'en' }, 'bg': { name: 'Български', code: 'bg' }, 'cs': { name: 'Čeština', code: 'cs' }, 'de': { name: 'Deutsch', code: 'de' }, - 'dk': { name: 'Dansk', code: 'dk' }, + 'da': { name: 'Dansk', code: 'da' }, 'el': { name: 'Ελληνικά', code: 'el' }, 'en': { name: 'English', code: 'en' }, 'es': { name: 'Español', code: 'es' }, @@ -34,12 +35,14 @@ Locale.languages = { 'nl': { name: 'Nederlands', code: 'nl' }, 'pl': { name: 'Polski', code: 'pl' }, 'pt': { name: 'Português', code: 'pt' }, + 'pt_BR': { name: 'Português (Brasil)', code: 'pt_BR' }, 'ru': { name: 'Русский', code: 'ru' }, 'si': { name: 'සිංහල', code: 'en' }, 'sk': { name: 'Slovenčina', code: 'sk' }, 'sl': { name: 'Slovenščina', code: 'sl' }, 'sr': { name: 'Srpski', code: 'sr' }, 'th': { name: 'ไทย', code: 'th' }, + 'uk': { name: 'Українська', code: 'ukr' }, 'zh': { name: '中文', code: 'zh_CN' } }; @@ -53,5 +56,11 @@ if (!(Locale.language in Locale.languages)) { Locale.language = 'en'; // default } -Ext.Loader.loadScript('/l10n/' + Locale.language + '.js'); +Ext.Ajax.request({ + url: '/l10n/' + Locale.language + '.json', + callback: function (options, success, response) { + Strings = Ext.decode(response.responseText); + } +}); + Ext.Loader.loadScript('//cdnjs.cloudflare.com/ajax/libs/extjs/6.0.0/classic/locale/locale-' + Locale.languages[Locale.language].code + '.js'); diff --git a/web/release.html b/web/release.html index 490a22551..27200b142 100644 --- a/web/release.html +++ b/web/release.html @@ -5,12 +5,13 @@ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <title>Traccar</title> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/extjs/6.0.0/classic/theme-neptune/resources/theme-neptune-all.css"> -<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/ol3/3.10.1/ol.min.css"> +<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/ol3/3.11.1/ol.min.css"> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css"> <link rel="stylesheet" href="app.css"> <script src="//cdnjs.cloudflare.com/ajax/libs/extjs/6.0.0/ext-all.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/extjs/6.0.0/classic/theme-neptune/theme-neptune.js"></script> -<script src="//cdnjs.cloudflare.com/ajax/libs/ol3/3.10.1/ol.min.js"></script> +<script src="//cdnjs.cloudflare.com/ajax/libs/ol3/3.11.1/ol-debug.min.js"></script> +<script src="arrowstyle.js"></script> <script src="locale.js"></script> <script type="text/javascript"> Ext.Loader.loadScript('app.min.js'); |