aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debug.xml20
-rw-r--r--pom.xml28
-rwxr-xr-xsetup/package.sh8
-rw-r--r--setup/unix/traccar.xml76
-rw-r--r--setup/windows/traccar.iss2
-rw-r--r--setup/windows/traccar.xml76
-rw-r--r--src/org/traccar/BasePipelineFactory.java4
-rw-r--r--src/org/traccar/BaseProtocolDecoder.java9
-rw-r--r--src/org/traccar/ExtendedObjectDecoder.java4
-rw-r--r--src/org/traccar/MainEventHandler.java14
-rw-r--r--src/org/traccar/RemoteAddressHandler.java3
-rw-r--r--src/org/traccar/ReverseGeocoderHandler.java2
-rw-r--r--src/org/traccar/WebDataHandler.java57
-rw-r--r--src/org/traccar/database/ConnectionManager.java17
-rw-r--r--src/org/traccar/database/DataManager.java8
-rw-r--r--src/org/traccar/database/QueryBuilder.java170
-rw-r--r--src/org/traccar/helper/DateBuilder.java18
-rw-r--r--src/org/traccar/helper/Log.java4
-rw-r--r--src/org/traccar/helper/ObdDecoder.java78
-rw-r--r--src/org/traccar/helper/Parser.java13
-rw-r--r--src/org/traccar/helper/PatternBuilder.java2
-rw-r--r--src/org/traccar/model/Command.java1
-rw-r--r--src/org/traccar/model/Device.java4
-rw-r--r--src/org/traccar/model/Event.java1
-rw-r--r--src/org/traccar/model/Extensible.java6
-rw-r--r--src/org/traccar/protocol/ApelProtocolDecoder.java43
-rw-r--r--src/org/traccar/protocol/Ardi01ProtocolDecoder.java85
-rw-r--r--src/org/traccar/protocol/AtrackProtocolDecoder.java189
-rw-r--r--src/org/traccar/protocol/AutoFon45ProtocolDecoder.java79
-rw-r--r--src/org/traccar/protocol/AutoFonProtocolDecoder.java27
-rw-r--r--src/org/traccar/protocol/Avl301ProtocolDecoder.java38
-rw-r--r--src/org/traccar/protocol/BceProtocolDecoder.java3
-rw-r--r--src/org/traccar/protocol/BlackKiteProtocolDecoder.java3
-rw-r--r--src/org/traccar/protocol/CalAmpProtocolDecoder.java56
-rw-r--r--src/org/traccar/protocol/CarTrackProtocolDecoder.java128
-rw-r--r--src/org/traccar/protocol/CastelProtocolDecoder.java237
-rw-r--r--src/org/traccar/protocol/CellocatorProtocolDecoder.java27
-rw-r--r--src/org/traccar/protocol/CityeasyProtocolDecoder.java105
-rw-r--r--src/org/traccar/protocol/EasyTrackProtocolDecoder.java137
-rw-r--r--src/org/traccar/protocol/EelinkProtocolDecoder.java9
-rw-r--r--src/org/traccar/protocol/EnforaProtocolDecoder.java132
-rw-r--r--src/org/traccar/protocol/Ev603ProtocolDecoder.java103
-rw-r--r--src/org/traccar/protocol/FlextrackProtocolDecoder.java151
-rw-r--r--src/org/traccar/protocol/FreedomProtocolDecoder.java3
-rw-r--r--src/org/traccar/protocol/GalileoProtocolDecoder.java6
-rw-r--r--src/org/traccar/protocol/GatorProtocolDecoder.java38
-rw-r--r--src/org/traccar/protocol/Gl100ProtocolDecoder.java93
-rw-r--r--src/org/traccar/protocol/Gl200ProtocolDecoder.java13
-rw-r--r--src/org/traccar/protocol/GlobalSatProtocolDecoder.java4
-rw-r--r--src/org/traccar/protocol/GoSafeProtocolDecoder.java6
-rw-r--r--src/org/traccar/protocol/GotopProtocolDecoder.java87
-rw-r--r--src/org/traccar/protocol/Gps103Protocol.java3
-rw-r--r--src/org/traccar/protocol/Gps103ProtocolDecoder.java14
-rw-r--r--src/org/traccar/protocol/Gps103ProtocolEncoder.java2
-rw-r--r--src/org/traccar/protocol/GpsGateProtocolDecoder.java88
-rw-r--r--src/org/traccar/protocol/GpsMarkerProtocolDecoder.java119
-rw-r--r--src/org/traccar/protocol/GpsmtaProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/Gt02ProtocolDecoder.java45
-rw-r--r--src/org/traccar/protocol/H02ProtocolDecoder.java3
-rw-r--r--src/org/traccar/protocol/HaicomProtocolDecoder.java138
-rw-r--r--src/org/traccar/protocol/HuabaoFrameDecoder.java58
-rw-r--r--src/org/traccar/protocol/HuabaoProtocol.java42
-rw-r--r--src/org/traccar/protocol/HuabaoProtocolDecoder.java47
-rw-r--r--src/org/traccar/protocol/IntellitracProtocolDecoder.java147
-rw-r--r--src/org/traccar/protocol/Jt600ProtocolDecoder.java142
-rw-r--r--src/org/traccar/protocol/KhdProtocolDecoder.java38
-rw-r--r--src/org/traccar/protocol/M2mProtocolDecoder.java36
-rw-r--r--src/org/traccar/protocol/MaxonProtocolDecoder.java133
-rw-r--r--src/org/traccar/protocol/MegastekProtocolDecoder.java5
-rw-r--r--src/org/traccar/protocol/MeitrackProtocolDecoder.java215
-rw-r--r--src/org/traccar/protocol/MiniFinderProtocolDecoder.java99
-rw-r--r--src/org/traccar/protocol/Mta6ProtocolDecoder.java21
-rw-r--r--src/org/traccar/protocol/MxtProtocolDecoder.java20
-rw-r--r--src/org/traccar/protocol/NavigilProtocolDecoder.java3
-rw-r--r--src/org/traccar/protocol/NavisProtocolDecoder.java73
-rw-r--r--src/org/traccar/protocol/NoranProtocolDecoder.java31
-rw-r--r--src/org/traccar/protocol/OrionProtocolDecoder.java30
-rw-r--r--src/org/traccar/protocol/OsmAndProtocolDecoder.java10
-rw-r--r--src/org/traccar/protocol/PiligrimProtocolDecoder.java23
-rw-r--r--src/org/traccar/protocol/ProgressProtocolDecoder.java75
-rw-r--r--src/org/traccar/protocol/Pt3000ProtocolDecoder.java94
-rw-r--r--src/org/traccar/protocol/Pt502ProtocolDecoder.java143
-rw-r--r--src/org/traccar/protocol/RuptelaProtocolDecoder.java11
-rw-r--r--src/org/traccar/protocol/Stl060ProtocolDecoder.java67
-rw-r--r--src/org/traccar/protocol/SuntechProtocolDecoder.java100
-rw-r--r--src/org/traccar/protocol/T55ProtocolDecoder.java23
-rw-r--r--src/org/traccar/protocol/T800xProtocol.java43
-rw-r--r--src/org/traccar/protocol/T800xProtocolDecoder.java162
-rw-r--r--src/org/traccar/protocol/TaipProtocolDecoder.java123
-rw-r--r--src/org/traccar/protocol/TelikProtocolDecoder.java88
-rw-r--r--src/org/traccar/protocol/TeltonikaProtocolDecoder.java3
-rw-r--r--src/org/traccar/protocol/Tk102ProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/Tk103ProtocolDecoder.java44
-rw-r--r--src/org/traccar/protocol/Tr20ProtocolDecoder.java131
-rw-r--r--src/org/traccar/protocol/Tr900ProtocolDecoder.java114
-rw-r--r--src/org/traccar/protocol/TrackboxProtocolDecoder.java133
-rw-r--r--src/org/traccar/protocol/TramigoProtocolDecoder.java4
-rw-r--r--src/org/traccar/protocol/TrvProtocol.java (renamed from src/org/traccar/protocol/MaxonProtocol.java)12
-rw-r--r--src/org/traccar/protocol/TrvProtocolDecoder.java125
-rw-r--r--src/org/traccar/protocol/UlbotechProtocolDecoder.java13
-rw-r--r--src/org/traccar/protocol/VisiontekProtocolDecoder.java5
-rw-r--r--src/org/traccar/protocol/WatchProtocol.java (renamed from src/org/traccar/protocol/Ev603Protocol.java)12
-rw-r--r--src/org/traccar/protocol/WatchProtocolDecoder.java146
-rw-r--r--src/org/traccar/protocol/WondexProtocolDecoder.java109
-rw-r--r--src/org/traccar/web/AsyncServlet.java8
-rw-r--r--test/org/traccar/ProtocolDecoderTest.java23
-rw-r--r--test/org/traccar/helper/ChannelBufferToolsTest.java13
-rw-r--r--test/org/traccar/helper/ObdDecoderTest.java19
-rw-r--r--test/org/traccar/helper/PatternBuilderTest.java2
-rw-r--r--test/org/traccar/protocol/Ardi01ProtocolDecoderTest.java4
-rw-r--r--test/org/traccar/protocol/AtrackProtocolDecoderTest.java29
-rw-r--r--test/org/traccar/protocol/AutoFon45ProtocolDecoderTest.java7
-rw-r--r--test/org/traccar/protocol/CarTrackProtocolDecoderTest.java4
-rw-r--r--test/org/traccar/protocol/CastelProtocolDecoderTest.java33
-rw-r--r--test/org/traccar/protocol/CityeasyProtocolDecoderTest.java12
-rw-r--r--test/org/traccar/protocol/EasyTrackProtocolDecoderTest.java5
-rw-r--r--test/org/traccar/protocol/EnforaProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/Ev603ProtocolDecoderTest.java39
-rw-r--r--test/org/traccar/protocol/FlextrackProtocolDecoderTest.java4
-rw-r--r--test/org/traccar/protocol/Gl100ProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/Gl200ProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/GotopProtocolDecoderTest.java11
-rw-r--r--test/org/traccar/protocol/Gps103ProtocolDecoderTest.java4
-rw-r--r--test/org/traccar/protocol/GpsGateProtocolDecoderTest.java20
-rw-r--r--test/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/GpsmtaProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/Gt02ProtocolDecoderTest.java5
-rw-r--r--test/org/traccar/protocol/HaicomProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/HuabaoFrameDecoderTest.java20
-rw-r--r--test/org/traccar/protocol/HuabaoProtocolDecoderTest.java18
-rw-r--r--test/org/traccar/protocol/IntellitracProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/Jt600ProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/MegastekProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/MeitrackProtocolDecoderTest.java8
-rw-r--r--test/org/traccar/protocol/MiniFinderProtocolDecoderTest.java30
-rw-r--r--test/org/traccar/protocol/NavisProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/Pt3000ProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/Pt502ProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/Stl060ProtocolDecoderTest.java5
-rw-r--r--test/org/traccar/protocol/SuntechProtocolDecoderTest.java9
-rw-r--r--test/org/traccar/protocol/T55ProtocolDecoderTest.java27
-rw-r--r--test/org/traccar/protocol/T800xProtocolDecoderTest.java30
-rw-r--r--test/org/traccar/protocol/TaipProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/TelikProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/Tk102ProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/Tk103ProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/Tr20ProtocolDecoderTest.java7
-rw-r--r--test/org/traccar/protocol/Tr900ProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/TrackboxProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/TrvProtocolDecoderTest.java28
-rw-r--r--test/org/traccar/protocol/UlbotechProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/WatchProtocolDecoderTest.java37
-rw-r--r--test/org/traccar/protocol/WondexProtocolDecoderTest.java14
-rwxr-xr-xtools/test-generator.py55
-rwxr-xr-xtools/test-integration.py26
-rwxr-xr-xtools/test-performance.py44
-rwxr-xr-xtools/translate.py54
-rw-r--r--web/.jscsrc3
-rw-r--r--web/.jshintignore1
-rw-r--r--web/app/Application.js8
-rw-r--r--web/app/AttributeFormatter.js2
-rw-r--r--web/app/Style.js30
-rw-r--r--web/app/controller/Root.js28
-rw-r--r--web/app/store/DistanceUnits.js2
-rw-r--r--web/app/store/SpeedUnits.js2
-rw-r--r--web/app/view/DevicesController.js7
-rw-r--r--web/app/view/Login.js5
-rw-r--r--web/app/view/LoginController.js12
-rw-r--r--web/app/view/Map.js41
-rw-r--r--web/app/view/MapController.js291
-rw-r--r--web/app/view/Register.js2
-rw-r--r--web/app/view/Report.js4
-rw-r--r--web/app/view/ReportController.js16
-rw-r--r--web/app/view/StateController.js98
-rw-r--r--web/app/view/UserDevicesController.js12
-rw-r--r--web/app/view/UsersController.js2
-rw-r--r--web/arrowstyle.js539
-rw-r--r--web/debug.html5
-rw-r--r--web/l10n/ar.json79
-rw-r--r--web/l10n/bg.js88
-rw-r--r--web/l10n/bg.json79
-rwxr-xr-xweb/l10n/cs.js89
-rw-r--r--web/l10n/cs.json79
-rw-r--r--web/l10n/da.json79
-rw-r--r--web/l10n/de.js86
-rw-r--r--web/l10n/de.json79
-rw-r--r--web/l10n/dk.js86
-rwxr-xr-xweb/l10n/el.js86
-rw-r--r--web/l10n/el.json79
-rw-r--r--web/l10n/en.js89
-rw-r--r--web/l10n/en.json79
-rw-r--r--web/l10n/es.js86
-rw-r--r--web/l10n/es.json79
-rw-r--r--web/l10n/fr.js86
-rw-r--r--web/l10n/fr.json79
-rwxr-xr-xweb/l10n/hu.js87
-rw-r--r--web/l10n/hu.json79
-rw-r--r--web/l10n/lt.js86
-rw-r--r--web/l10n/lt.json79
-rw-r--r--web/l10n/nl.js86
-rw-r--r--web/l10n/nl.json79
-rw-r--r--web/l10n/pl.js86
-rw-r--r--web/l10n/pl.json79
-rw-r--r--web/l10n/pt.js86
-rw-r--r--web/l10n/pt.json79
-rw-r--r--web/l10n/pt_BR.json79
-rw-r--r--web/l10n/ru.js86
-rw-r--r--web/l10n/ru.json79
-rwxr-xr-xweb/l10n/si.js88
-rw-r--r--web/l10n/si.json79
-rw-r--r--web/l10n/sk.js86
-rw-r--r--web/l10n/sk.json79
-rw-r--r--web/l10n/sl.js86
-rw-r--r--web/l10n/sl.json79
-rw-r--r--web/l10n/sr.js86
-rw-r--r--web/l10n/sr.json79
-rw-r--r--web/l10n/th.js86
-rw-r--r--web/l10n/th.json79
-rw-r--r--web/l10n/uk.json79
-rw-r--r--web/l10n/zh.js86
-rw-r--r--web/l10n/zh.json79
-rw-r--r--web/locale.js13
-rw-r--r--web/release.html5
223 files changed, 6135 insertions, 5066 deletions
diff --git a/debug.xml b/debug.xml
index 43070f9ec..47f17bdae 100644
--- a/debug.xml
+++ b/debug.xml
@@ -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>
diff --git a/pom.xml b/pom.xml
index ec1219d7b..5403f40c1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -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');