aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--schema/changelog-4.0.xml56
-rw-r--r--schema/changelog-master.xml1
-rw-r--r--setup/default.xml22
-rw-r--r--src/org/traccar/WebDataHandler.java1
-rw-r--r--src/org/traccar/database/DataManager.java5
-rw-r--r--src/org/traccar/model/Position.java2
-rw-r--r--src/org/traccar/protocol/AquilaProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/EsealProtocol.java53
-rw-r--r--src/org/traccar/protocol/EsealProtocolDecoder.java155
-rw-r--r--src/org/traccar/protocol/EsealProtocolEncoder.java45
-rw-r--r--src/org/traccar/protocol/FreematicsProtocol.java43
-rw-r--r--src/org/traccar/protocol/FreematicsProtocolDecoder.java103
-rw-r--r--src/org/traccar/protocol/Gps103ProtocolDecoder.java14
-rw-r--r--src/org/traccar/protocol/L100FrameDecoder.java24
-rw-r--r--src/org/traccar/protocol/L100ProtocolDecoder.java109
-rw-r--r--src/org/traccar/protocol/RetranslatorFrameDecoder.java38
-rw-r--r--src/org/traccar/protocol/RetranslatorProtocol.java42
-rw-r--r--src/org/traccar/protocol/RetranslatorProtocolDecoder.java119
-rw-r--r--src/org/traccar/protocol/SviasProtocol.java58
-rw-r--r--src/org/traccar/protocol/SviasProtocolDecoder.java103
-rw-r--r--src/org/traccar/protocol/SviasProtocolEncoder.java51
-rw-r--r--templates/export/stops.xlsxbin11699 -> 11062 bytes
-rw-r--r--templates/export/summary.xlsxbin11592 -> 10812 bytes
-rw-r--r--templates/export/trips.xlsxbin9299 -> 11374 bytes
-rw-r--r--test/org/traccar/database/DataManagerTest.java22
-rw-r--r--test/org/traccar/protocol/EsealProtocolDecoderTest.java33
-rw-r--r--test/org/traccar/protocol/EsealProtocolEncoderTest.java24
-rw-r--r--test/org/traccar/protocol/FreematicsProtocolDecoderTest.java18
-rw-r--r--test/org/traccar/protocol/L100FrameDecoderTest.java4
-rw-r--r--test/org/traccar/protocol/L100ProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/RetranslatorProtocolDecoderTest.java21
-rw-r--r--test/org/traccar/protocol/SviasProtocolDecoderTest.java24
32 files changed, 1159 insertions, 39 deletions
diff --git a/schema/changelog-4.0.xml b/schema/changelog-4.0.xml
new file mode 100644
index 000000000..04e9fe0c4
--- /dev/null
+++ b/schema/changelog-4.0.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"
+ logicalFilePath="changelog-4.0">
+
+ <changeSet author="author" id="changelog-4.0-renaming">
+
+ <preConditions onFail="MARK_RAN">
+ <not>
+ <tableExists tableName="tc_servers" />
+ </not>
+ </preConditions>
+
+ <renameTable oldTableName="attributes" newTableName="tc_attributes" />
+ <renameTable oldTableName="calendars" newTableName="tc_calendars" />
+ <renameTable oldTableName="commands" newTableName="tc_commands" />
+ <renameTable oldTableName="device_attribute" newTableName="tc_device_attribute" />
+ <renameTable oldTableName="device_command" newTableName="tc_device_command" />
+ <renameTable oldTableName="device_driver" newTableName="tc_device_driver" />
+ <renameTable oldTableName="device_geofence" newTableName="tc_device_geofence" />
+ <renameTable oldTableName="device_maintenance" newTableName="tc_device_maintenance" />
+ <renameTable oldTableName="device_notification" newTableName="tc_device_notification" />
+ <renameTable oldTableName="devices" newTableName="tc_devices" />
+ <renameTable oldTableName="drivers" newTableName="tc_drivers" />
+ <renameTable oldTableName="events" newTableName="tc_events" />
+ <renameTable oldTableName="geofences" newTableName="tc_geofences" />
+ <renameTable oldTableName="group_attribute" newTableName="tc_group_attribute" />
+ <renameTable oldTableName="group_command" newTableName="tc_group_command" />
+ <renameTable oldTableName="group_driver" newTableName="tc_group_driver" />
+ <renameTable oldTableName="group_geofence" newTableName="tc_group_geofence" />
+ <renameTable oldTableName="group_maintenance" newTableName="tc_group_maintenance" />
+ <renameTable oldTableName="group_notification" newTableName="tc_group_notification" />
+ <renameTable oldTableName="groups" newTableName="tc_groups" />
+ <renameTable oldTableName="maintenances" newTableName="tc_maintenances" />
+ <renameTable oldTableName="notifications" newTableName="tc_notifications" />
+ <renameTable oldTableName="positions" newTableName="tc_positions" />
+ <renameTable oldTableName="servers" newTableName="tc_servers" />
+ <renameTable oldTableName="statistics" newTableName="tc_statistics" />
+ <renameTable oldTableName="user_attribute" newTableName="tc_user_attribute" />
+ <renameTable oldTableName="user_calendar" newTableName="tc_user_calendar" />
+ <renameTable oldTableName="user_command" newTableName="tc_user_command" />
+ <renameTable oldTableName="user_device" newTableName="tc_user_device" />
+ <renameTable oldTableName="user_driver" newTableName="tc_user_driver" />
+ <renameTable oldTableName="user_geofence" newTableName="tc_user_geofence" />
+ <renameTable oldTableName="user_group" newTableName="tc_user_group" />
+ <renameTable oldTableName="user_maintenance" newTableName="tc_user_maintenance" />
+ <renameTable oldTableName="user_notification" newTableName="tc_user_notification" />
+ <renameTable oldTableName="user_user" newTableName="tc_user_user" />
+ <renameTable oldTableName="users" newTableName="tc_users" />
+
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml
index 3e7944238..e8fbc0c4b 100644
--- a/schema/changelog-master.xml
+++ b/schema/changelog-master.xml
@@ -18,4 +18,5 @@
<include file="changelog-3.15.xml" relativeToChangelogFile="true" />
<include file="changelog-3.16.xml" relativeToChangelogFile="true" />
<include file="changelog-3.17.xml" relativeToChangelogFile="true" />
+ <include file="changelog-4.0.xml" relativeToChangelogFile="true" />
</databaseChangeLog>
diff --git a/setup/default.xml b/setup/default.xml
index bdc7eee1c..f5ec4b9bf 100644
--- a/setup/default.xml
+++ b/setup/default.xml
@@ -19,7 +19,7 @@
<entry key='logger.file'>./logs/tracker-server.log</entry>
<entry key='filter.enable'>true</entry>
- <entry key='filter.future'>3600</entry>
+ <entry key='filter.future'>86400</entry>
<entry key='event.enable'>true</entry>
<entry key='event.ignoreDuplicateAlerts'>true</entry>
@@ -41,36 +41,36 @@
<entry key='database.changelog'>./schema/changelog-master.xml</entry>
<entry key='database.loginUser'>
- SELECT * FROM users
+ SELECT * FROM tc_users
WHERE email = :email OR login = :email
</entry>
<entry key='database.selectPositions'>
- SELECT * FROM positions WHERE deviceId = :deviceId AND fixTime BETWEEN :from AND :to ORDER BY fixTime
+ SELECT * FROM tc_positions WHERE deviceId = :deviceId AND fixTime BETWEEN :from AND :to ORDER BY fixTime
</entry>
<entry key='database.selectLatestPositions'>
- SELECT positions.* FROM positions INNER JOIN devices ON positions.id = devices.positionid;
+ SELECT tc_positions.* FROM tc_positions INNER JOIN tc_devices ON tc_positions.id = tc_devices.positionid;
</entry>
<entry key='database.updateLatestPosition'>
- UPDATE devices SET positionId = :id WHERE id = :deviceId
+ UPDATE tc_devices SET positionId = :id WHERE id = :deviceId
</entry>
<entry key='database.selectEvents'>
- SELECT * FROM events WHERE deviceId = :deviceId AND serverTime BETWEEN :from AND :to ORDER BY serverTime
+ SELECT * FROM tc_events WHERE deviceId = :deviceId AND serverTime BETWEEN :from AND :to ORDER BY serverTime
</entry>
<entry key='database.deletePositions'>
- DELETE FROM positions WHERE serverTime &lt; :serverTime AND id NOT IN (SELECT positionId FROM devices WHERE positionId IS NOT NULL)
+ DELETE FROM tc_positions WHERE serverTime &lt; :serverTime AND id NOT IN (SELECT positionId FROM tc_devices WHERE positionId IS NOT NULL)
</entry>
<entry key='database.deleteEvents'>
- DELETE FROM events WHERE serverTime &lt; :serverTime
+ DELETE FROM tc_events WHERE serverTime &lt; :serverTime
</entry>
<entry key='database.selectStatistics'>
- SELECT * FROM statistics WHERE captureTime BETWEEN :from AND :to ORDER BY captureTime
+ SELECT * FROM tc_statistics WHERE captureTime BETWEEN :from AND :to ORDER BY captureTime
</entry>
<!-- PROTOCOL CONFIG -->
@@ -242,5 +242,9 @@
<entry key='pt60.port'>5164</entry>
<entry key='telemax.port'>5165</entry>
<entry key='sabertek.port'>5166</entry>
+ <entry key='retranslator.port'>5167</entry>
+ <entry key='svias.port'>5168</entry>
+ <entry key='eseal.port'>5169</entry>
+ <entry key='freematics.port'>5170</entry>
</properties>
diff --git a/src/org/traccar/WebDataHandler.java b/src/org/traccar/WebDataHandler.java
index 79221de9a..763493437 100644
--- a/src/org/traccar/WebDataHandler.java
+++ b/src/org/traccar/WebDataHandler.java
@@ -98,6 +98,7 @@ public class WebDataHandler extends BaseDataHandler {
.replace("{altitude}", String.valueOf(position.getAltitude()))
.replace("{speed}", String.valueOf(position.getSpeed()))
.replace("{course}", String.valueOf(position.getCourse()))
+ .replace("{accuracy}", String.valueOf(position.getAccuracy()))
.replace("{statusCode}", calculateStatus(position));
if (position.getAddress() != null) {
diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java
index ae5ec2d5f..06dd26b17 100644
--- a/src/org/traccar/database/DataManager.java
+++ b/src/org/traccar/database/DataManager.java
@@ -273,11 +273,12 @@ public class DataManager {
if (propertyName.equals("ManagedUser")) {
propertyName = "User";
}
- return Introspector.decapitalize(owner.getSimpleName()) + "_" + Introspector.decapitalize(propertyName);
+ return "tc_" + Introspector.decapitalize(owner.getSimpleName())
+ + "_" + Introspector.decapitalize(propertyName);
}
private static String getObjectsTableName(Class<?> clazz) {
- String result = Introspector.decapitalize(clazz.getSimpleName());
+ String result = "tc_" + Introspector.decapitalize(clazz.getSimpleName());
// Add "s" ending if object name is not plural already
if (!result.endsWith("s")) {
result += "s";
diff --git a/src/org/traccar/model/Position.java b/src/org/traccar/model/Position.java
index b0fe7a79b..4b327cbd2 100644
--- a/src/org/traccar/model/Position.java
+++ b/src/org/traccar/model/Position.java
@@ -112,6 +112,8 @@ public class Position extends Message {
public static final String ALARM_POWER_OFF = "powerOff";
public static final String ALARM_POWER_ON = "powerOn";
public static final String ALARM_DOOR = "door";
+ public static final String ALARM_LOCK = "lock";
+ public static final String ALARM_UNLOCK = "unlock";
public static final String ALARM_GEOFENCE = "geofence";
public static final String ALARM_GEOFENCE_ENTER = "geofenceEnter";
public static final String ALARM_GEOFENCE_EXIT = "geofenceExit";
diff --git a/src/org/traccar/protocol/AquilaProtocolDecoder.java b/src/org/traccar/protocol/AquilaProtocolDecoder.java
index 97d4ca79f..8e4343ac4 100644
--- a/src/org/traccar/protocol/AquilaProtocolDecoder.java
+++ b/src/org/traccar/protocol/AquilaProtocolDecoder.java
@@ -302,7 +302,7 @@ public class AquilaProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_ALARM, Position.ALARM_SOS);
if (channel != null) {
String password = Context.getIdentityManager().lookupAttributeString(
- position.getDeviceId(), getProtocolName() + ".language", "aquila123", true);
+ position.getDeviceId(), getProtocolName() + ".password", "aquila123", true);
channel.writeAndFlush(new NetworkMessage(
"#set$" + id + "@" + password + "#EMR_MODE:0*", remoteAddress));
}
diff --git a/src/org/traccar/protocol/EsealProtocol.java b/src/org/traccar/protocol/EsealProtocol.java
new file mode 100644
index 000000000..c778021ec
--- /dev/null
+++ b/src/org/traccar/protocol/EsealProtocol.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.handler.codec.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.TrackerServer;
+import org.traccar.model.Command;
+
+import java.util.List;
+
+public class EsealProtocol extends BaseProtocol {
+
+ public EsealProtocol() {
+ super("eseal");
+ setSupportedDataCommands(
+ Command.TYPE_CUSTOM,
+ Command.TYPE_ALARM_ARM,
+ Command.TYPE_ALARM_DISARM);
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ServerBootstrap(), getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
+ pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
+ pipeline.addLast("objectEncoder", new EsealProtocolEncoder());
+ pipeline.addLast("objectDecoder", new EsealProtocolDecoder(EsealProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/EsealProtocolDecoder.java b/src/org/traccar/protocol/EsealProtocolDecoder.java
new file mode 100644
index 000000000..90f360d66
--- /dev/null
+++ b/src/org/traccar/protocol/EsealProtocolDecoder.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.Context;
+import org.traccar.DeviceSession;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+public class EsealProtocolDecoder extends BaseProtocolDecoder {
+
+ private String config;
+
+ public EsealProtocolDecoder(EsealProtocol protocol) {
+ super(protocol);
+ config = Context.getConfig().getString(getProtocolName() + ".config");
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("##S,")
+ .expression("[^,]+,") // device type
+ .number("(d+),") // device id
+ .number("d+,") // customer id
+ .expression("[^,]+,") // firmware version
+ .expression("([^,]+),") // type
+ .number("(d+),") // index
+ .number("(dddd)-(dd)-(dd),") // date
+ .number("(dd):(dd):(dd),") // time
+ .number("d+,") // interval
+ .expression("([AV]),") // validity
+ .number("(d+.d+)([NS]) ") // latitude
+ .number("(d+.d+)([EW]),") // longitude
+ .number("(d+),") // course
+ .number("(d+),") // speed
+ .expression("([^,]+),") // door
+ .number("(d+.d+),") // acceleration
+ .expression("([^,]+),") // nfc
+ .number("(d+.d+),") // battery
+ .number("(-?d+),") // rssi
+ .text("E##")
+ .compile();
+
+ private void sendResponse(Channel channel, String prefix, String type, String payload) {
+ if (channel != null) {
+ channel.write(prefix + type + "," + payload + ",E##\r\n");
+ }
+ }
+
+ private String decodeAlarm(String type) {
+ switch (type) {
+ case "Event-Door":
+ return Position.ALARM_DOOR;
+ case "Event-Shock":
+ return Position.ALARM_SHOCK;
+ case "Event-Drop":
+ return Position.ALARM_FALL_DOWN;
+ case "Event-Lock":
+ return Position.ALARM_LOCK;
+ case "Event-RC-Unlock":
+ return Position.ALARM_UNLOCK;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ String sentence = (String) msg;
+ Parser parser = new Parser(PATTERN, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ String type = parser.next();
+ String prefix = sentence.substring(0, sentence.indexOf(type));
+ int index = parser.nextInt();
+
+ position.set(Position.KEY_INDEX, index);
+ position.set(Position.KEY_ALARM, decodeAlarm(type));
+
+ switch (type) {
+ case "Startup":
+ sendResponse(channel, prefix, type + " ACK", index + "," + config);
+ break;
+ case "Normal":
+ case "Button-Normal":
+ case "Termination":
+ case "Event-Door":
+ case "Event-Shock":
+ case "Event-Drop":
+ case "Event-Lock":
+ case "Event-RC-Unlock":
+ sendResponse(channel, prefix, type + " ACK", String.valueOf(index));
+ break;
+ default:
+ break;
+ }
+
+ position.setTime(parser.nextDateTime());
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setCourse(parser.nextInt());
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt()));
+
+ switch (parser.next()) {
+ case "Open":
+ position.set(Position.KEY_DOOR, true);
+ break;
+ case "Close":
+ position.set(Position.KEY_DOOR, false);
+ break;
+ default:
+ break;
+ }
+
+ position.set(Position.KEY_ACCELERATION, parser.nextDouble());
+ position.set("nfc", parser.next());
+ position.set(Position.KEY_BATTERY, parser.nextDouble());
+ position.set(Position.KEY_RSSI, parser.nextInt());
+
+ return position;
+ }
+
+}
diff --git a/src/org/traccar/protocol/EsealProtocolEncoder.java b/src/org/traccar/protocol/EsealProtocolEncoder.java
new file mode 100644
index 000000000..886bb80b1
--- /dev/null
+++ b/src/org/traccar/protocol/EsealProtocolEncoder.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.traccar.StringProtocolEncoder;
+import org.traccar.helper.Log;
+import org.traccar.model.Command;
+
+public class EsealProtocolEncoder extends StringProtocolEncoder {
+
+ @Override
+ protected Object encodeCommand(Command command) {
+
+ switch (command.getType()) {
+ case Command.TYPE_CUSTOM:
+ return formatCommand(
+ command, "##S,eSeal,{%s},256,3.0.8,{%s},E##", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
+ case Command.TYPE_ALARM_ARM:
+ return formatCommand(
+ command, "##S,eSeal,{%s},256,3.0.8,RC-Power Control,Power OFF,E##", Command.KEY_UNIQUE_ID);
+ case Command.TYPE_ALARM_DISARM:
+ return formatCommand(
+ command, "##S,eSeal,{%s},256,3.0.8,RC-Unlock,E##", Command.KEY_UNIQUE_ID);
+ default:
+ Log.warning(new UnsupportedOperationException(command.getType()));
+ break;
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/protocol/FreematicsProtocol.java b/src/org/traccar/protocol/FreematicsProtocol.java
new file mode 100644
index 000000000..551c7e619
--- /dev/null
+++ b/src/org/traccar/protocol/FreematicsProtocol.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.handler.codec.string.StringDecoder;
+import org.traccar.BaseProtocol;
+import org.traccar.TrackerServer;
+
+import java.util.List;
+
+public class FreematicsProtocol extends BaseProtocol {
+
+ public FreematicsProtocol() {
+ super("freematics");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ConnectionlessBootstrap(), getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("stringDecoder", new StringDecoder());
+ pipeline.addLast("objectDecoder", new FreematicsProtocolDecoder(FreematicsProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/FreematicsProtocolDecoder.java b/src/org/traccar/protocol/FreematicsProtocolDecoder.java
new file mode 100644
index 000000000..66e451d6d
--- /dev/null
+++ b/src/org/traccar/protocol/FreematicsProtocolDecoder.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.helper.DateBuilder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.Date;
+
+public class FreematicsProtocolDecoder extends BaseProtocolDecoder {
+
+ public FreematicsProtocolDecoder(FreematicsProtocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ String sentence = (String) msg;
+ int startIndex = sentence.indexOf('#');
+ int endIndex = sentence.indexOf('*');
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(0, startIndex));
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+ position.setValid(true);
+
+ DateBuilder dateBuilder = new DateBuilder(new Date());
+
+ for (String pair : sentence.substring(startIndex + 1, endIndex).split(",")) {
+ String[] data = pair.split("=");
+ int key = Integer.parseInt(data[0], 16);
+ String value = data[1];
+ switch (key) {
+ case 0x11:
+ value = ("000000" + value).substring(value.length());
+ dateBuilder.setDateReverse(
+ Integer.parseInt(value.substring(0, 2)),
+ Integer.parseInt(value.substring(2, 4)),
+ Integer.parseInt(value.substring(4)));
+ break;
+ case 0x10:
+ value = ("00000000" + value).substring(value.length());
+ dateBuilder.setTime(
+ Integer.parseInt(value.substring(0, 2)),
+ Integer.parseInt(value.substring(2, 4)),
+ Integer.parseInt(value.substring(4, 6)),
+ Integer.parseInt(value.substring(6)) * 10);
+ break;
+ case 0xA:
+ position.setLatitude(Double.parseDouble(value));
+ break;
+ case 0xB:
+ position.setLongitude(Double.parseDouble(value));
+ break;
+ case 0xC:
+ position.setAltitude(Integer.parseInt(value));
+ break;
+ case 0xD:
+ position.setLatitude(UnitsConverter.knotsFromKph(Integer.parseInt(value)));
+ break;
+ case 0xE:
+ position.setCourse(Integer.parseInt(value));
+ break;
+ case 0xF:
+ position.set(Position.KEY_SATELLITES, Integer.parseInt(value));
+ break;
+ default:
+ position.set(data[0], value);
+ break;
+ }
+
+ }
+
+ position.setTime(dateBuilder.getDate());
+
+ return position;
+ }
+
+}
diff --git a/src/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/org/traccar/protocol/Gps103ProtocolDecoder.java
index 7a66a48bd..2b797d05a 100644
--- a/src/org/traccar/protocol/Gps103ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gps103ProtocolDecoder.java
@@ -67,13 +67,13 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
.expression("([EW]),").optional()
.number("(d+)(dd.d+),") // longitude (dddmm.mmmm)
.expression("([EW])?,").optional()
- .number("(d+.?d*)?,").optional() // speed
- .number("(d+.?d*)?,").optional() // course
- .number("(d+.?d*)?,").optional() // altitude
- .number("([01])?,").optional() // ignition
- .number("([01])?,").optional() // door
- .number("(?:(d+.d+)%)?,").optional() // fuel 1
- .number("(?:(d+.d+)%)?,").optional() // fuel 2
+ .number("(d+.?d*)?").optional() // speed
+ .number(",(d+.?d*)?").optional() // course
+ .number(",(d+.?d*)?").optional() // altitude
+ .number(",([01])?").optional() // ignition
+ .number(",([01])?").optional() // door
+ .number(",(?:(d+.d+)%)?").optional() // fuel 1
+ .number(",(?:(d+.d+)%)?").optional() // fuel 2
.number("(-?d+)?") // temperature
.groupEnd()
.any()
diff --git a/src/org/traccar/protocol/L100FrameDecoder.java b/src/org/traccar/protocol/L100FrameDecoder.java
index d407ac0b5..b7caa14f4 100644
--- a/src/org/traccar/protocol/L100FrameDecoder.java
+++ b/src/org/traccar/protocol/L100FrameDecoder.java
@@ -26,22 +26,32 @@ public class L100FrameDecoder extends BaseFrameDecoder {
protected Object decode(
ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception {
- if (buf.readableBytes() < 80) {
+ if (buf.readableBytes() < 10) {
return null;
}
- int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x02);
- if (index == -1) {
- index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x04);
+ int header = buf.getByte(buf.readerIndex());
+ boolean obd = header == 'L' || header == 'H';
+
+ int index;
+ if (obd) {
+ index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*');
+ } else {
+ index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x02);
if (index == -1) {
- return null;
+ index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x04);
+ if (index == -1) {
+ return null;
+ }
}
}
index += 2; // checksum
- if (buf.readableBytes() >= index - buf.readerIndex()) {
- buf.skipBytes(2); // header
+ if (buf.writerIndex() >= index) {
+ if (!obd) {
+ buf.skipBytes(2); // header
+ }
ByteBuf frame = buf.readRetainedSlice(index - buf.readerIndex() - 2);
buf.skipBytes(2); // footer
return frame;
diff --git a/src/org/traccar/protocol/L100ProtocolDecoder.java b/src/org/traccar/protocol/L100ProtocolDecoder.java
index ad93baf67..7c652c95a 100644
--- a/src/org/traccar/protocol/L100ProtocolDecoder.java
+++ b/src/org/traccar/protocol/L100ProtocolDecoder.java
@@ -18,6 +18,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
+import org.traccar.helper.Checksum;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -66,23 +67,59 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
.text("ATL")
.compile();
+ private static final Pattern PATTERN_OBD = new PatternBuilder()
+ .expression("[LH],") // archive
+ .text("ATL,")
+ .number("(d{15}),") // imei
+ .number("(d+),") // type
+ .number("(d+),") // index
+ .groupBegin()
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .expression("([AV]),") // validity
+ .number("(d+.d+);([NS]),") // latitude
+ .number("(d+.d+);([EW]),") // longitude
+ .number("(d+),") // speed
+ .number("(d+),") // course
+ .number("(d+.d+),") // odometer
+ .number("(d+.d+),") // battery
+ .number("(d+),") // rssi
+ .number("(d+),") // mcc
+ .number("(d+),") // mnc
+ .number("(d+),") // lac
+ .number("(x+),") // cid
+ .number("#(d)(d)(d)(d),") // status
+ .number("(d),") // overspeed
+ .text("ATL,")
+ .groupEnd("?")
+ .compile();
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
+ if (sentence.startsWith("L") || sentence.startsWith("H")) {
+ return decodeObd(channel, remoteAddress, sentence);
+ } else {
+ return decodeNormal(channel, remoteAddress, sentence);
+ }
+ }
+
+ private Object decodeNormal(Channel channel, SocketAddress remoteAddress, String sentence) {
+
Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
return null;
}
- Position position = new Position(getProtocolName());
-
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
if (deviceSession == null) {
return null;
}
+
+ Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
DateBuilder dateBuilder = new DateBuilder()
@@ -112,4 +149,72 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Object decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) {
+
+ Parser parser = new Parser(PATTERN_OBD, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ String imei = parser.next();
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ int type = parser.nextInt();
+ int index = parser.nextInt();
+
+ if (type == 1) {
+ if (channel != null) {
+ String response = "@" + imei + ",00," + index + ",";
+ response += "*" + (char) Checksum.xor(response);
+ channel.write(response, remoteAddress);
+ }
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY));
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setSpeed(parser.nextInt());
+ position.setCourse(parser.nextInt());
+
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
+ position.set(Position.KEY_BATTERY, parser.nextDouble());
+
+ int rssi = parser.nextInt();
+ position.setNetwork(new Network(CellTower.from(
+ parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextHexInt(), rssi)));
+
+ position.set(Position.KEY_IGNITION, parser.nextInt() == 1);
+ parser.next(); // reserved
+
+ switch (parser.nextInt()) {
+ case 0:
+ position.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
+ break;
+ case 2:
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
+ break;
+ case 1:
+ position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
+ break;
+ default:
+ break;
+ }
+
+ position.set(Position.KEY_CHARGE, parser.nextInt() == 1);
+
+ if (parser.nextInt() == 1) {
+ position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED);
+ }
+
+ return position;
+ }
+
}
diff --git a/src/org/traccar/protocol/RetranslatorFrameDecoder.java b/src/org/traccar/protocol/RetranslatorFrameDecoder.java
new file mode 100644
index 000000000..1836fb26e
--- /dev/null
+++ b/src/org/traccar/protocol/RetranslatorFrameDecoder.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.frame.FrameDecoder;
+
+public class RetranslatorFrameDecoder extends FrameDecoder {
+
+ @Override
+ protected Object decode(
+ ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception {
+
+ int length = 4 + ChannelBuffers.swapInt(buf.getInt(buf.readerIndex()));
+ if (buf.readableBytes() >= length) {
+ return buf.readBytes(length);
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/src/org/traccar/protocol/RetranslatorProtocol.java b/src/org/traccar/protocol/RetranslatorProtocol.java
new file mode 100644
index 000000000..0421390b2
--- /dev/null
+++ b/src/org/traccar/protocol/RetranslatorProtocol.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.traccar.BaseProtocol;
+import org.traccar.TrackerServer;
+
+import java.util.List;
+
+public class RetranslatorProtocol extends BaseProtocol {
+
+ public RetranslatorProtocol() {
+ super("retranslator");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ServerBootstrap(), getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new RetranslatorFrameDecoder());
+ pipeline.addLast("objectDecoder", new RetranslatorProtocolDecoder(RetranslatorProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/RetranslatorProtocolDecoder.java b/src/org/traccar/protocol/RetranslatorProtocolDecoder.java
new file mode 100644
index 000000000..756b0bcaf
--- /dev/null
+++ b/src/org/traccar/protocol/RetranslatorProtocolDecoder.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.nio.ByteOrder;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+
+public class RetranslatorProtocolDecoder extends BaseProtocolDecoder {
+
+ public RetranslatorProtocolDecoder(RetranslatorProtocol protocol) {
+ super(protocol);
+ }
+
+ private double readDouble(ChannelBuffer buf) {
+ byte[] bytes = new byte[8];
+ buf.readBytes(bytes);
+ return ChannelBuffers.wrappedBuffer(ByteOrder.LITTLE_ENDIAN, bytes).readDouble();
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ if (channel != null) {
+ channel.write(ChannelBuffers.wrappedBuffer(new byte[]{0x11}));
+ }
+
+ ChannelBuffer buf = (ChannelBuffer) msg;
+
+ buf.readUnsignedInt(); // length
+
+ int idLength = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x00) - buf.readerIndex();
+ String id = buf.readBytes(idLength).toString(StandardCharsets.US_ASCII);
+ buf.readByte();
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+ position.setTime(new Date(buf.readUnsignedInt() * 1000));
+
+ buf.readUnsignedInt(); // bit flags
+
+ while (buf.readable()) {
+
+ buf.readUnsignedShort(); // block type
+ int blockEnd = buf.readInt() + buf.readerIndex();
+ buf.readUnsignedByte(); // security attribute
+ int dataType = buf.readUnsignedByte();
+
+ int nameLength = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x00) - buf.readerIndex();
+ String name = buf.readBytes(nameLength).toString(StandardCharsets.US_ASCII);
+ buf.readByte();
+
+ if (name.equals("posinfo")) {
+ position.setValid(true);
+ position.setLongitude(readDouble(buf));
+ position.setLatitude(readDouble(buf));
+ position.setAltitude(readDouble(buf));
+ position.setSpeed(buf.readShort());
+ position.setCourse(buf.readShort());
+ position.set(Position.KEY_SATELLITES, buf.readByte());
+ } else {
+ switch (dataType) {
+ case 1:
+ int len = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x00) - buf.readerIndex();
+ position.set(name, buf.readBytes(len).toString(StandardCharsets.US_ASCII));
+ buf.readByte();
+ break;
+ case 3:
+ position.set(name, buf.readInt());
+ break;
+ case 4:
+ position.set(name, readDouble(buf));
+ break;
+ case 5:
+ position.set(name, buf.readLong());
+ break;
+ default:
+ break;
+ }
+ }
+
+ buf.readerIndex(blockEnd);
+
+ }
+
+ if (position.getLatitude() == 0 && position.getLongitude() == 0) {
+ getLastLocation(position, position.getDeviceTime());
+ }
+
+ return position;
+ }
+
+}
diff --git a/src/org/traccar/protocol/SviasProtocol.java b/src/org/traccar/protocol/SviasProtocol.java
new file mode 100644
index 000000000..badf3d091
--- /dev/null
+++ b/src/org/traccar/protocol/SviasProtocol.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.handler.codec.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;
+import org.traccar.model.Command;
+
+public class SviasProtocol extends BaseProtocol {
+
+ public SviasProtocol() {
+ super("svias");
+ setSupportedDataCommands(
+ Command.TYPE_CUSTOM,
+ Command.TYPE_POSITION_SINGLE,
+ Command.TYPE_SET_ODOMETER,
+ Command.TYPE_ENGINE_STOP,
+ Command.TYPE_ENGINE_RESUME,
+ Command.TYPE_ALARM_ARM,
+ Command.TYPE_ALARM_DISARM,
+ Command.TYPE_ALARM_REMOVE);
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ServerBootstrap(), getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, "]"));
+ pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
+ pipeline.addLast("objectEncoder", new SviasProtocolEncoder());
+ pipeline.addLast("objectDecoder", new SviasProtocolDecoder(SviasProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/SviasProtocolDecoder.java b/src/org/traccar/protocol/SviasProtocolDecoder.java
new file mode 100644
index 000000000..c2ea33ae9
--- /dev/null
+++ b/src/org/traccar/protocol/SviasProtocolDecoder.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.helper.BitUtil;
+import org.traccar.helper.PatternBuilder;
+
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+import org.traccar.DeviceSession;
+import org.traccar.helper.Parser;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+public class SviasProtocolDecoder extends BaseProtocolDecoder {
+
+ public SviasProtocolDecoder(SviasProtocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("[") // delimiter
+ .number("d{4},") // hardware version
+ .number("d{4},") // software version
+ .number("d+,") // index
+ .number("(d+),") // imei
+ .number("d+,") // hour meter
+ .number("(d+)(dd)(dd),") // date (dmmyy)
+ .number("(d+)(dd)(dd),") // time (hmmss)
+ .number("(-?)(d+)(dd)(d{5}),") // latitude
+ .number("(-?)(d+)(dd)(d{5}),") // longitude
+ .number("(d+),") // speed
+ .number("(d+),") // course
+ .number("(d+),") // odometer
+ .number("(d+),") // input
+ .number("(d+),") // output / status
+ .number("(d),")
+ .number("(d),")
+ .number("(d+),") // power
+ .number("(d+),") // battery level
+ .number("(d+),") // rssi
+ .any()
+ .compile();
+
+ @Override
+ protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg)
+ throws Exception {
+
+ if (channel != null) {
+ channel.write("@");
+ }
+
+ Parser parser = new Parser(PATTERN, (String) msg);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble() * 0.01));
+ position.setCourse(parser.nextDouble() * 0.01);
+
+ position.set(Position.KEY_ODOMETER, parser.nextInt() * 100);
+
+ int input = parser.nextInt();
+ int output = parser.nextInt();
+
+ position.set(Position.KEY_ALARM, BitUtil.check(input, 0) ? Position.ALARM_SOS : null);
+ position.set(Position.KEY_IGNITION, BitUtil.check(input, 4));
+ position.setValid(BitUtil.check(output, 0));
+
+ position.set(Position.KEY_POWER, parser.nextInt() * 0.001);
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
+ position.set(Position.KEY_RSSI, parser.nextInt());
+
+ return position;
+ }
+
+}
diff --git a/src/org/traccar/protocol/SviasProtocolEncoder.java b/src/org/traccar/protocol/SviasProtocolEncoder.java
new file mode 100644
index 000000000..c26ee2032
--- /dev/null
+++ b/src/org/traccar/protocol/SviasProtocolEncoder.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.traccar.StringProtocolEncoder;
+import org.traccar.helper.Log;
+import org.traccar.model.Command;
+
+public class SviasProtocolEncoder extends StringProtocolEncoder {
+
+ @Override
+ protected Object encodeCommand(Command command) {
+ switch (command.getType()) {
+ case Command.TYPE_CUSTOM:
+ return formatCommand(command, "{%s}", Command.KEY_DATA);
+ case Command.TYPE_POSITION_SINGLE:
+ return formatCommand(command, "AT+STR=1*");
+ case Command.TYPE_SET_ODOMETER:
+ return formatCommand(command, "AT+ODT={%s}*", Command.KEY_DATA);
+ case Command.TYPE_ENGINE_STOP:
+ return formatCommand(command, "AT+OUT=1,1*");
+ case Command.TYPE_ENGINE_RESUME:
+ return formatCommand(command, "AT+OUT=1,0*");
+ case Command.TYPE_ALARM_ARM:
+ return formatCommand(command, "AT+OUT=2,1*");
+ case Command.TYPE_ALARM_DISARM:
+ return formatCommand(command, "AT+OUT=2,0*");
+ case Command.TYPE_ALARM_REMOVE:
+ return formatCommand(command, "AT+PNC=600*");
+ default:
+ Log.warning(new UnsupportedOperationException(command.getType()));
+ break;
+ }
+ return null;
+ }
+
+}
diff --git a/templates/export/stops.xlsx b/templates/export/stops.xlsx
index e4a5248ca..1892f7c9a 100644
--- a/templates/export/stops.xlsx
+++ b/templates/export/stops.xlsx
Binary files differ
diff --git a/templates/export/summary.xlsx b/templates/export/summary.xlsx
index 94d2b9e79..a4d55d721 100644
--- a/templates/export/summary.xlsx
+++ b/templates/export/summary.xlsx
Binary files differ
diff --git a/templates/export/trips.xlsx b/templates/export/trips.xlsx
index ef803bc4b..6536011e3 100644
--- a/templates/export/trips.xlsx
+++ b/templates/export/trips.xlsx
Binary files differ
diff --git a/test/org/traccar/database/DataManagerTest.java b/test/org/traccar/database/DataManagerTest.java
index f9945c994..23043e96e 100644
--- a/test/org/traccar/database/DataManagerTest.java
+++ b/test/org/traccar/database/DataManagerTest.java
@@ -18,11 +18,11 @@ public class DataManagerTest {
@Test
public void constructObjectQuery() {
- assertEquals("SELECT * FROM users",
+ assertEquals("SELECT * FROM tc_users",
DataManager.constructObjectQuery(DataManager.ACTION_SELECT_ALL, User.class, false));
- assertEquals("DELETE FROM groups WHERE id = :id",
+ assertEquals("DELETE FROM tc_groups WHERE id = :id",
DataManager.constructObjectQuery(DataManager.ACTION_DELETE, Group.class, false));
- assertEquals("SELECT * FROM positions WHERE id = :id",
+ assertEquals("SELECT * FROM tc_positions WHERE id = :id",
DataManager.constructObjectQuery(DataManager.ACTION_SELECT, Position.class, false));
String insertDevice = DataManager.constructObjectQuery(DataManager.ACTION_INSERT, Device.class, false);
@@ -52,28 +52,28 @@ public class DataManagerTest {
@Test
public void constructPermissionsQuery() {
- assertEquals("SELECT userId, deviceId FROM user_device",
+ assertEquals("SELECT userId, deviceId FROM tc_user_device",
DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, User.class, Device.class));
- assertEquals("SELECT userId, managedUserId FROM user_user",
+ assertEquals("SELECT userId, managedUserId FROM tc_user_user",
DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, User.class, ManagedUser.class));
- assertEquals("SELECT deviceId, driverId FROM device_driver",
+ assertEquals("SELECT deviceId, driverId FROM tc_device_driver",
DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, Device.class, Driver.class));
- assertEquals("SELECT groupId, geofenceId FROM group_geofence",
+ assertEquals("SELECT groupId, geofenceId FROM tc_group_geofence",
DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, Group.class, Geofence.class));
- assertEquals("INSERT INTO user_device (userId, deviceId) VALUES (:userId, :deviceId)",
+ assertEquals("INSERT INTO tc_user_device (userId, deviceId) VALUES (:userId, :deviceId)",
DataManager.constructPermissionQuery(DataManager.ACTION_INSERT, User.class, Device.class));
- assertEquals("DELETE FROM user_user WHERE userId = :userId AND managedUserId = :managedUserId",
+ assertEquals("DELETE FROM tc_user_user WHERE userId = :userId AND managedUserId = :managedUserId",
DataManager.constructPermissionQuery(DataManager.ACTION_DELETE, User.class, ManagedUser.class));
- assertEquals("INSERT INTO device_geofence (deviceId, geofenceId) VALUES (:deviceId, :geofenceId)",
+ assertEquals("INSERT INTO tc_device_geofence (deviceId, geofenceId) VALUES (:deviceId, :geofenceId)",
DataManager.constructPermissionQuery(DataManager.ACTION_INSERT, Device.class, Geofence.class));
- assertEquals("DELETE FROM group_attribute WHERE groupId = :groupId AND attributeId = :attributeId",
+ assertEquals("DELETE FROM tc_group_attribute WHERE groupId = :groupId AND attributeId = :attributeId",
DataManager.constructPermissionQuery(DataManager.ACTION_DELETE, Group.class, Attribute.class));
}
diff --git a/test/org/traccar/protocol/EsealProtocolDecoderTest.java b/test/org/traccar/protocol/EsealProtocolDecoderTest.java
new file mode 100644
index 000000000..c14652dd1
--- /dev/null
+++ b/test/org/traccar/protocol/EsealProtocolDecoderTest.java
@@ -0,0 +1,33 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class EsealProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ EsealProtocolDecoder decoder = new EsealProtocolDecoder(new EsealProtocol());
+
+ verifyPosition(decoder, text(
+ "##S,eSeal,1000821,256,3.0.6,Normal,34,2017-08-31,08:14:40,15,A,25.708828N 100.372870W,10,0,Close,0.71,0:0:3:0,3.8,-73,E##"));
+
+ verifyPosition(decoder, text(
+ "##S,eSeal,1000821,256,3.0.6,Startup,1,2017-08-31,02:01:19,3,V,0.000000N 0.000000E,0,0,Close,3.25,0:0:5:0,3.8,-93,E##"));
+
+ verifyNull(decoder, text(
+ "##S,eSeal,1000821,256,3.0.6,Startup OK,1,180,30,30,16,1,E##"));
+
+ verifyNull(decoder, text(
+ "##S,eSeal,1000821,256,3.0.6,Startup OK,1,180,30,30,16,1,E##"));
+
+ verifyPosition(decoder, text(
+ "##S,eSeal,1000898,256,3.0.6,Normal,6,2017-09-06,23:48:39,3,V,0.000000N 0.000000E,0,0,Close,1.0,0:0:3:0,4.0,-81,E##"));
+
+ verifyNull(decoder, text(
+ "##S,eSeal,1000898,256,3.0.6,RC-NFC DEL ACK,,E##"));
+
+ }
+
+}
diff --git a/test/org/traccar/protocol/EsealProtocolEncoderTest.java b/test/org/traccar/protocol/EsealProtocolEncoderTest.java
new file mode 100644
index 000000000..16f00d69b
--- /dev/null
+++ b/test/org/traccar/protocol/EsealProtocolEncoderTest.java
@@ -0,0 +1,24 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+import org.traccar.model.Command;
+
+import static org.junit.Assert.assertEquals;
+
+public class EsealProtocolEncoderTest extends ProtocolTest {
+
+ @Test
+ public void testEncode() throws Exception {
+
+ EsealProtocolEncoder encoder = new EsealProtocolEncoder();
+
+ Command command = new Command();
+ command.setDeviceId(1);
+ command.setType(Command.TYPE_ALARM_DISARM);
+
+ assertEquals("##S,eSeal,123456789012345,256,3.0.8,RC-Unlock,E##", encoder.encodeCommand(command));
+
+ }
+
+}
diff --git a/test/org/traccar/protocol/FreematicsProtocolDecoderTest.java b/test/org/traccar/protocol/FreematicsProtocolDecoderTest.java
new file mode 100644
index 000000000..f629f68df
--- /dev/null
+++ b/test/org/traccar/protocol/FreematicsProtocolDecoderTest.java
@@ -0,0 +1,18 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class FreematicsProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ FreematicsProtocolDecoder decoder = new FreematicsProtocolDecoder(new FreematicsProtocol());
+
+ verifyPosition(decoder, text(
+ "1#0=68338,10D=79,30=1010,105=199,10C=4375,104=56,111=62,20=0;-1;95,10=6454200,A=-32.727482,B=150.150301,C=159,D=0,F=5,24=1250*7A"));
+
+ }
+
+}
diff --git a/test/org/traccar/protocol/L100FrameDecoderTest.java b/test/org/traccar/protocol/L100FrameDecoderTest.java
index 7cb385d3e..a94f2eb0d 100644
--- a/test/org/traccar/protocol/L100FrameDecoderTest.java
+++ b/test/org/traccar/protocol/L100FrameDecoderTest.java
@@ -11,6 +11,10 @@ public class L100FrameDecoderTest extends ProtocolTest {
L100FrameDecoder decoder = new L100FrameDecoder();
verifyFrame(
+ binary("4c2c41544c2c3836363739353033303437373935322c30312c303033352c"),
+ decoder.decode(null, null, binary("4c2c41544c2c3836363739353033303437373935322c30312c303033352c2a28")));
+
+ verifyFrame(
binary("41544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735242c2330313130303131313030313031302c4e2e432c4e2e432c4e2e432c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c"),
decoder.decode(null, null, binary("200141544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735242c2330313130303131313030313031302c4e2e432c4e2e432c4e2e432c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c027a")));
diff --git a/test/org/traccar/protocol/L100ProtocolDecoderTest.java b/test/org/traccar/protocol/L100ProtocolDecoderTest.java
index 1e48ecef5..65a5a1afe 100644
--- a/test/org/traccar/protocol/L100ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/L100ProtocolDecoderTest.java
@@ -11,6 +11,12 @@ public class L100ProtocolDecoderTest extends ProtocolTest {
L100ProtocolDecoder decoder = new L100ProtocolDecoder(new L100Protocol());
verifyPosition(decoder, text(
+ "H,ATL,866795030478513,02,0981,054448,230318,A,28.633486;N,77.222595;E,0,154,1.14,4.2,18,404,4,88,ad7b,#1031,0,ATL,"));
+
+ verifyNull(decoder, text(
+ "L,ATL,866795030477952,01,0035,"));
+
+ verifyPosition(decoder, text(
"ATL861693039769518,$GPRMC,074930.000,A,2838.0112,N,07713.3602,E,0000,223.36,290518,,,A*7E,#01111011000100,0.012689,0,0,2.572415,0,4.015,22,404,4,88,3ad5,0,0.01,1.4_800F_VTS3D3_gen_peri_myn,,internet,00000000,ATL"));
verifyPosition(decoder, text(
diff --git a/test/org/traccar/protocol/RetranslatorProtocolDecoderTest.java b/test/org/traccar/protocol/RetranslatorProtocolDecoderTest.java
new file mode 100644
index 000000000..680570763
--- /dev/null
+++ b/test/org/traccar/protocol/RetranslatorProtocolDecoderTest.java
@@ -0,0 +1,21 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class RetranslatorProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ RetranslatorProtocolDecoder decoder = new RetranslatorProtocolDecoder(new RetranslatorProtocol());
+
+ verifyPosition(decoder, binary(
+ "74000000333533393736303133343435343835004B0BFB70000000030BBB000000270102706F73696E666F00A027AFDF5D9848403AC7253383DD4B400000000000805A40003601460B0BBB0000001200047077725F657874002B8716D9CE973B400BBB00000011010361766C5F696E707574730000000001"));
+
+ verifyPosition(decoder, binary(
+ "1f010000333533353439303930303934373330005b129b5f000000010bbb000000270102706f73696e666f004e3be14e5ec356c0e0e92f6201282c400000000000000000000000130d0bbb0000000a00036d636300000002c00bbb0000000a00036d6e6300000000010bbb0000000a00036c616300000001490bbb0000000e000363656c6c5f696400000056590bbb0000000a000361636300000000000bbb000000100003646174615f6d6f6465000000000e0bbb0000001200036770735f7265616c5f757000000000000bbb0000000d000373657269616c000000089b0bbb0000001000016d73675f747970650030783232000bbb000000110004637573746f6d0000000000000033400bbb0000001200046d696c65616765000000000000000000"));
+
+ }
+
+}
diff --git a/test/org/traccar/protocol/SviasProtocolDecoderTest.java b/test/org/traccar/protocol/SviasProtocolDecoderTest.java
new file mode 100644
index 000000000..3bf355a15
--- /dev/null
+++ b/test/org/traccar/protocol/SviasProtocolDecoderTest.java
@@ -0,0 +1,24 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class SviasProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ SviasProtocolDecoder decoder = new SviasProtocolDecoder(new SviasProtocol());
+
+ verifyPosition(decoder, text(
+ "[7061,3041,57,20324277,710,40618,141342,-93155840,-371754060,0,20469,0,16,1,0,0,11323,100,9,,32,4695"));
+
+ verifyPosition(decoder, text(
+ "[7041,3041,8629,20856286,710,60618,201027,-92268040,-371346250,7994,31844,38271,16,1,0,0,13416,100,0,0,5089"));
+
+ verifyPosition(decoder, text(
+ "[7051,3041,15270,30179873,710,70618,40335,-94679080,-360604930,0,35454,23148,0,1,0,0,12542,100,13,32,4971"));
+
+ }
+
+}