aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2018-06-12 13:49:59 +1200
committerAnton Tananaev <anton.tananaev@gmail.com>2018-06-12 13:49:59 +1200
commit69a4af1c2b419fd7cc6356bcc2bf760969a73f95 (patch)
tree4192ef221be88b024d96422e274836f4c6b33922 /src
parent1dc1e06cfd4b7b23775984a254723b2d06b4f1dd (diff)
parent86ad45c63c9a9e9bee59a8cc621416e1396f9c89 (diff)
downloadtrackermap-server-69a4af1c2b419fd7cc6356bcc2bf760969a73f95.tar.gz
trackermap-server-69a4af1c2b419fd7cc6356bcc2bf760969a73f95.tar.bz2
trackermap-server-69a4af1c2b419fd7cc6356bcc2bf760969a73f95.zip
Merge branch 'master' into netty4
# Conflicts: # src/org/traccar/protocol/AquilaProtocolDecoder.java # src/org/traccar/protocol/L100FrameDecoder.java
Diffstat (limited to 'src')
-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
18 files changed, 948 insertions, 19 deletions
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;
+ }
+
+}