aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/org/traccar/BasePipelineFactory.java62
-rw-r--r--src/org/traccar/MainEventHandler.java42
-rw-r--r--src/org/traccar/protocol/CellocatorProtocolDecoder.java62
-rw-r--r--src/org/traccar/protocol/EelinkProtocolDecoder.java25
-rw-r--r--src/org/traccar/protocol/EelinkProtocolEncoder.java1
-rw-r--r--src/org/traccar/protocol/Gps103ProtocolDecoder.java47
-rw-r--r--src/org/traccar/protocol/Gt06ProtocolDecoder.java39
-rw-r--r--src/org/traccar/protocol/H02ProtocolDecoder.java77
-rw-r--r--src/org/traccar/protocol/ItsProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/NeosProtocol.java37
-rw-r--r--src/org/traccar/protocol/NeosProtocolDecoder.java98
-rw-r--r--src/org/traccar/protocol/SatsolProtocol.java37
-rw-r--r--src/org/traccar/protocol/SatsolProtocolDecoder.java104
-rw-r--r--src/org/traccar/protocol/TotemProtocolDecoder.java44
-rw-r--r--src/org/traccar/protocol/UproProtocolDecoder.java12
-rw-r--r--src/org/traccar/protocol/VtfmsProtocolDecoder.java25
16 files changed, 595 insertions, 119 deletions
diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java
index 401c42d8b..b45e3a280 100644
--- a/src/org/traccar/BasePipelineFactory.java
+++ b/src/org/traccar/BasePipelineFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2019 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.
@@ -44,6 +44,7 @@ import org.traccar.processing.ComputedAttributesHandler;
import org.traccar.processing.CopyAttributesHandler;
import java.net.InetSocketAddress;
+import java.net.SocketAddress;
import java.util.Map;
public abstract class BasePipelineFactory extends ChannelInitializer<Channel> {
@@ -99,25 +100,29 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> {
private static class NetworkMessageHandler extends ChannelDuplexHandler {
@Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (ctx.channel() instanceof DatagramChannel) {
DatagramPacket packet = (DatagramPacket) msg;
ctx.fireChannelRead(new NetworkMessage(packet.content(), packet.sender()));
- } else {
+ } else if (msg instanceof ByteBuf) {
ByteBuf buffer = (ByteBuf) msg;
ctx.fireChannelRead(new NetworkMessage(buffer, ctx.channel().remoteAddress()));
}
}
@Override
- public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
- NetworkMessage message = (NetworkMessage) msg;
- if (ctx.channel() instanceof DatagramChannel) {
- InetSocketAddress recipient = (InetSocketAddress) message.getRemoteAddress();
- InetSocketAddress sender = (InetSocketAddress) ctx.channel().localAddress();
- ctx.write(new DatagramPacket((ByteBuf) message.getMessage(), recipient, sender), promise);
+ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
+ if (msg instanceof NetworkMessage) {
+ NetworkMessage message = (NetworkMessage) msg;
+ if (ctx.channel() instanceof DatagramChannel) {
+ InetSocketAddress recipient = (InetSocketAddress) message.getRemoteAddress();
+ InetSocketAddress sender = (InetSocketAddress) ctx.channel().localAddress();
+ ctx.write(new DatagramPacket((ByteBuf) message.getMessage(), recipient, sender), promise);
+ } else {
+ ctx.write(message.getMessage(), promise);
+ }
} else {
- ctx.write(message.getMessage(), promise);
+ ctx.write(msg, promise);
}
}
@@ -138,7 +143,17 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> {
}
public void log(ChannelHandlerContext ctx, boolean downstream, Object o) {
- NetworkMessage networkMessage = (NetworkMessage) o;
+ if (o instanceof NetworkMessage) {
+ NetworkMessage networkMessage = (NetworkMessage) o;
+ if (networkMessage.getMessage() instanceof ByteBuf) {
+ log(ctx, downstream, networkMessage.getRemoteAddress(), (ByteBuf) networkMessage.getMessage());
+ }
+ } else if (o instanceof ByteBuf) {
+ log(ctx, downstream, ctx.channel().remoteAddress(), (ByteBuf) o);
+ }
+ }
+
+ public void log(ChannelHandlerContext ctx, boolean downstream, SocketAddress remoteAddress, ByteBuf buf) {
StringBuilder message = new StringBuilder();
message.append("[").append(ctx.channel().id().asShortText()).append(": ");
@@ -149,15 +164,15 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> {
message.append(" < ");
}
- if (networkMessage.getRemoteAddress() != null) {
- message.append(((InetSocketAddress) networkMessage.getRemoteAddress()).getHostString());
+ if (remoteAddress instanceof InetSocketAddress) {
+ message.append(((InetSocketAddress) remoteAddress).getHostString());
} else {
- message.append("null");
+ message.append("unknown");
}
message.append("]");
message.append(" HEX: ");
- message.append(ByteBufUtil.hexDump((ByteBuf) networkMessage.getMessage()));
+ message.append(ByteBufUtil.hexDump(buf));
LOGGER.info(message.toString());
}
@@ -267,18 +282,15 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> {
pipeline.addLast(new NetworkMessageHandler());
pipeline.addLast(new StandardLoggingHandler());
- addProtocolHandlers(new PipelineBuilder() {
- @Override
- public void addLast(ChannelHandler handler) {
- if (!(handler instanceof BaseProtocolDecoder || handler instanceof BaseProtocolEncoder)) {
- if (handler instanceof ChannelInboundHandler) {
- handler = new WrapperInboundHandler((ChannelInboundHandler) handler);
- } else {
- handler = new WrapperOutboundHandler((ChannelOutboundHandler) handler);
- }
+ addProtocolHandlers(handler -> {
+ if (!(handler instanceof BaseProtocolDecoder || handler instanceof BaseProtocolEncoder)) {
+ if (handler instanceof ChannelInboundHandler) {
+ handler = new WrapperInboundHandler((ChannelInboundHandler) handler);
+ } else {
+ handler = new WrapperOutboundHandler((ChannelOutboundHandler) handler);
}
- pipeline.addLast(handler);
}
+ pipeline.addLast(handler);
});
addHandlers(
diff --git a/src/org/traccar/MainEventHandler.java b/src/org/traccar/MainEventHandler.java
index d4e1ff860..c905508e0 100644
--- a/src/org/traccar/MainEventHandler.java
+++ b/src/org/traccar/MainEventHandler.java
@@ -35,18 +35,19 @@ import java.util.Set;
public class MainEventHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(GeocoderHandler.class);
- private static final String DEFAULT_LOGGER_EVENTS = "time,position,speed,course,accuracy,result";
+
+ private static final String DEFAULT_LOGGER_ATTRIBUTES = "time,position,speed,course,accuracy,result";
private final Set<String> connectionlessProtocols = new HashSet<>();
- private final Set<String> logEvents;
+ private final Set<String> logAttributes = new LinkedHashSet<>();
public MainEventHandler() {
String connectionlessProtocolList = Context.getConfig().getString("status.ignoreOffline");
if (connectionlessProtocolList != null) {
connectionlessProtocols.addAll(Arrays.asList(connectionlessProtocolList.split(",")));
}
- logEvents = new LinkedHashSet<>(Arrays.asList(
- Context.getConfig().getString("logger.events", DEFAULT_LOGGER_EVENTS).split(",")));
+ logAttributes.addAll(Arrays.asList(
+ Context.getConfig().getString("logger.attributes", DEFAULT_LOGGER_ATTRIBUTES).split(",")));
}
@Override
@@ -62,51 +63,50 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter {
String uniqueId = Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId();
- // Log position
- StringBuilder s = new StringBuilder();
- s.append(formatChannel(ctx.channel())).append(" ");
- s.append("id: ").append(uniqueId);
- for (String event : logEvents) {
- switch (event) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(formatChannel(ctx.channel())).append(" ");
+ builder.append("id: ").append(uniqueId);
+ for (String attribute : logAttributes) {
+ switch (attribute) {
case "time":
- s.append(", time: ").append(DateUtil.formatDate(position.getFixTime(), false));
+ builder.append(", time: ").append(DateUtil.formatDate(position.getFixTime(), false));
break;
case "position":
- s.append(", lat: ").append(String.format("%.5f", position.getLatitude()));
- s.append(", lon: ").append(String.format("%.5f", position.getLongitude()));
+ builder.append(", lat: ").append(String.format("%.5f", position.getLatitude()));
+ builder.append(", lon: ").append(String.format("%.5f", position.getLongitude()));
break;
case "speed":
if (position.getSpeed() > 0) {
- s.append(", speed: ").append(String.format("%.1f", position.getSpeed()));
+ builder.append(", speed: ").append(String.format("%.1f", position.getSpeed()));
}
break;
case "course":
- s.append(", course: ").append(String.format("%.1f", position.getCourse()));
+ builder.append(", course: ").append(String.format("%.1f", position.getCourse()));
break;
case "accuracy":
if (position.getAccuracy() > 0) {
- s.append(", accuracy: ").append(String.format("%.1f", position.getAccuracy()));
+ builder.append(", accuracy: ").append(String.format("%.1f", position.getAccuracy()));
}
break;
case "outdated":
if (position.getOutdated()) {
- s.append(", outdated");
+ builder.append(", outdated");
}
break;
case "invalid":
if (!position.getValid()) {
- s.append(", invalid");
+ builder.append(", invalid");
}
break;
default:
- Object value = position.getAttributes().get(event);
+ Object value = position.getAttributes().get(attribute);
if (value != null) {
- s.append(", ").append(event).append(": ").append(value);
+ builder.append(", ").append(attribute).append(": ").append(value);
}
break;
}
}
- LOGGER.info(s.toString());
+ LOGGER.info(builder.toString());
Context.getStatisticsManager().registerMessageStored(position.getDeviceId());
}
diff --git a/src/org/traccar/protocol/CellocatorProtocolDecoder.java b/src/org/traccar/protocol/CellocatorProtocolDecoder.java
index fb805658a..453d8d7e7 100644
--- a/src/org/traccar/protocol/CellocatorProtocolDecoder.java
+++ b/src/org/traccar/protocol/CellocatorProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2019 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.
@@ -88,6 +88,8 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder {
ByteBuf buf = (ByteBuf) msg;
+ boolean alternative = buf.getByte(buf.readerIndex() + 3) != 'P';
+
buf.skipBytes(4); // system code
int type = buf.readUnsignedByte();
long deviceUniqueId = buf.readUnsignedIntLE();
@@ -111,40 +113,60 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_VERSION_HW, buf.readUnsignedByte());
position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte());
- position.set("protocolVersion", buf.readUnsignedByte());
+ buf.readUnsignedByte(); // protocol version
- position.set(Position.KEY_STATUS, buf.getUnsignedByte(buf.readerIndex()) & 0x0f);
+ position.set(Position.KEY_STATUS, buf.readUnsignedByte() & 0x0f);
- int operator = (buf.readUnsignedByte() & 0xf0) << 4;
- operator += buf.readUnsignedByte();
+ if (alternative) {
+ buf.readUnsignedByte(); // configuration flags
+ } else {
+ buf.readUnsignedByte(); // operator
+ }
buf.readUnsignedByte(); // reason data
position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
position.set("mode", buf.readUnsignedByte());
- position.set(Position.PREFIX_IO + 1, buf.readUnsignedIntLE());
-
- operator <<= 8;
- operator += buf.readUnsignedByte();
- position.set(Position.KEY_OPERATOR, operator);
+ position.set(Position.KEY_INPUT, buf.readUnsignedIntLE());
+
+ if (alternative) {
+ buf.readUnsignedByte(); // input
+ position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE());
+ position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE());
+ } else {
+ buf.readUnsignedByte(); // operator
+ position.set(Position.PREFIX_ADC + 1, buf.readUnsignedIntLE());
+ }
- position.set(Position.PREFIX_ADC + 1, buf.readUnsignedIntLE());
position.set(Position.KEY_ODOMETER, buf.readUnsignedMediumLE());
- buf.skipBytes(6); // multi-purpose data
- position.set(Position.KEY_GPS, buf.readUnsignedShortLE());
- position.set("locationStatus", buf.readUnsignedByte());
- position.set("mode1", buf.readUnsignedByte());
- position.set("mode2", buf.readUnsignedByte());
+ buf.skipBytes(6); // multi-purpose data
+ buf.readUnsignedShortLE(); // fix time
+ buf.readUnsignedByte(); // location status
+ buf.readUnsignedByte(); // mode 1
+ buf.readUnsignedByte(); // mode 2
position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
position.setValid(true);
- position.setLongitude(buf.readIntLE() / Math.PI * 180 / 100000000);
- position.setLatitude(buf.readIntLE() / Math.PI * 180 / 100000000.0);
+
+ if (alternative) {
+ position.setLongitude(buf.readIntLE() / 10000000.0);
+ position.setLatitude(buf.readIntLE() / 10000000.0);
+ } else {
+ position.setLongitude(buf.readIntLE() / Math.PI * 180 / 100000000);
+ position.setLatitude(buf.readIntLE() / Math.PI * 180 / 100000000);
+ }
+
position.setAltitude(buf.readIntLE() * 0.01);
- position.setSpeed(UnitsConverter.knotsFromMps(buf.readIntLE() * 0.01));
- position.setCourse(buf.readUnsignedShortLE() / Math.PI * 180.0 / 1000.0);
+
+ if (alternative) {
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedIntLE()));
+ position.setCourse(buf.readUnsignedShortLE() / 1000.0);
+ } else {
+ position.setSpeed(UnitsConverter.knotsFromMps(buf.readUnsignedIntLE() * 0.01));
+ position.setCourse(buf.readUnsignedShortLE() / Math.PI * 180.0 / 1000.0);
+ }
DateBuilder dateBuilder = new DateBuilder()
.setTimeReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
diff --git a/src/org/traccar/protocol/EelinkProtocolDecoder.java b/src/org/traccar/protocol/EelinkProtocolDecoder.java
index bffefbddf..14bf44fbf 100644
--- a/src/org/traccar/protocol/EelinkProtocolDecoder.java
+++ b/src/org/traccar/protocol/EelinkProtocolDecoder.java
@@ -17,6 +17,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
+import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.socket.DatagramChannel;
import org.traccar.BaseProtocolDecoder;
@@ -62,13 +63,6 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_CAMERA_INFO = 0x1E;
public static final int MSG_CAMERA_DATA = 0x1F;
- private void sendResponse(Channel channel, SocketAddress remoteAddress, String uniqueId, int type, int index) {
- if (channel != null) {
- channel.writeAndFlush(new NetworkMessage(EelinkProtocolEncoder.encodeContent(
- channel instanceof DatagramChannel, uniqueId, type, index, null), remoteAddress));
- }
- }
-
private String decodeAlarm(Short value) {
switch (value) {
case 0x01:
@@ -273,6 +267,10 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
position.set("co2", buf.readUnsignedInt());
}
+ if (buf.readableBytes() >= 2) {
+ position.set(Position.PREFIX_TEMP + 2, buf.readUnsignedShort() / 16.0);
+ }
+
}
return position;
@@ -352,7 +350,18 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
int index = buf.readUnsignedShort();
if (type != MSG_GPS && type != MSG_DATA) {
- sendResponse(channel, remoteAddress, uniqueId, type, index);
+ ByteBuf content = Unpooled.buffer();
+ if (type == MSG_LOGIN) {
+ content.writeInt((int) (System.currentTimeMillis() / 1000));
+ content.writeByte(1); // protocol version
+ content.writeByte(0); // action mask
+ }
+ ByteBuf response = EelinkProtocolEncoder.encodeContent(
+ channel instanceof DatagramChannel, uniqueId, type, index, content);
+ content.release();
+ if (channel != null) {
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
+ }
}
if (type == MSG_LOGIN) {
diff --git a/src/org/traccar/protocol/EelinkProtocolEncoder.java b/src/org/traccar/protocol/EelinkProtocolEncoder.java
index c005fbc67..8f33441fb 100644
--- a/src/org/traccar/protocol/EelinkProtocolEncoder.java
+++ b/src/org/traccar/protocol/EelinkProtocolEncoder.java
@@ -69,6 +69,7 @@ public class EelinkProtocolEncoder extends BaseProtocolEncoder {
}
result.writeBytes(buf);
+ buf.release();
return result;
}
diff --git a/src/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/org/traccar/protocol/Gps103ProtocolDecoder.java
index 1fbae15ce..27b94739b 100644
--- a/src/org/traccar/protocol/Gps103ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gps103ProtocolDecoder.java
@@ -15,11 +15,15 @@
*/
package org.traccar.protocol;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
+import org.traccar.Context;
import org.traccar.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -34,6 +38,9 @@ import java.util.regex.Pattern;
public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
+ private int photoPackets = 0;
+ private ByteBuf photo;
+
public Gps103ProtocolDecoder(Protocol protocol) {
super(protocol);
}
@@ -190,6 +197,9 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
if (channel != null) {
channel.writeAndFlush(new NetworkMessage("**,imei:" + imei + ",E;", remoteAddress));
}
+ } else if (alarm.startsWith("vt")) {
+ photoPackets = Integer.parseInt(alarm.substring(2));
+ photo = Unpooled.buffer();
} else if (alarm.equals("acc on")) {
position.set(Position.KEY_IGNITION, true);
} else if (alarm.equals("acc off")) {
@@ -336,6 +346,39 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Position decodePhoto(Channel channel, SocketAddress remoteAddress, String sentence) {
+
+ String imei = sentence.substring(5, 5 + 15);
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(
+ sentence.substring(24, sentence.endsWith(";") ? sentence.length() - 1 : sentence.length())));
+ int index = buf.readUnsignedShortLE();
+ photo.writeBytes(buf, buf.readerIndex() + 2, buf.readableBytes() - 4);
+
+ if (index + 1 >= photoPackets) {
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, null);
+
+ try {
+ position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(imei, photo, "jpg"));
+ } finally {
+ photoPackets = 0;
+ photo.release();
+ photo = null;
+ }
+
+ return position;
+ } else {
+ return null;
+ }
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -365,7 +408,9 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
}
}
- if (sentence.contains("OBD")) {
+ if (sentence.substring(21, 21 + 2).equals("vr")) {
+ return decodePhoto(channel, remoteAddress, sentence);
+ } else if (sentence.substring(21, 21 + 3).contains("OBD")) {
return decodeObd(channel, remoteAddress, sentence);
} else if (sentence.endsWith("*")) {
return decodeAlternative(channel, remoteAddress, sentence);
diff --git a/src/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/org/traccar/protocol/Gt06ProtocolDecoder.java
index f9c65f08b..6388455b5 100644
--- a/src/org/traccar/protocol/Gt06ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gt06ProtocolDecoder.java
@@ -67,7 +67,6 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_GPS_LBS_STATUS_3 = 0x27;
public static final int MSG_LBS_MULTIPLE = 0x28;
public static final int MSG_LBS_WIFI = 0x2C;
- public static final int MSG_LBS_PHONE = 0x17;
public static final int MSG_LBS_EXTEND = 0x18;
public static final int MSG_LBS_STATUS = 0x19;
public static final int MSG_GPS_PHONE = 0x1A;
@@ -389,7 +388,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
- private Object decodeBasic(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception {
+ private Object decodeBasic(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
int length = buf.readUnsignedByte();
int dataLength = length - 5;
@@ -488,7 +487,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
} else if (type == MSG_WIFI || type == MSG_WIFI_2) {
- return decodeWifi(buf, deviceSession);
+ return decodeWifi(channel, buf, deviceSession, type);
} else if (type == MSG_INFO) {
@@ -559,18 +558,19 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- private Object decodeWifi(ByteBuf buf, DeviceSession deviceSession) throws Exception {
+ private Object decodeWifi(Channel channel, ByteBuf buf, DeviceSession deviceSession, int type) {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
+ ByteBuf time = buf.readSlice(6);
DateBuilder dateBuilder = new DateBuilder()
- .setYear(BcdUtil.readInteger(buf, 2))
- .setMonth(BcdUtil.readInteger(buf, 2))
- .setDay(BcdUtil.readInteger(buf, 2))
- .setHour(BcdUtil.readInteger(buf, 2))
- .setMinute(BcdUtil.readInteger(buf, 2))
- .setSecond(BcdUtil.readInteger(buf, 2));
+ .setYear(BcdUtil.readInteger(time, 2))
+ .setMonth(BcdUtil.readInteger(time, 2))
+ .setDay(BcdUtil.readInteger(time, 2))
+ .setHour(BcdUtil.readInteger(time, 2))
+ .setMinute(BcdUtil.readInteger(time, 2))
+ .setSecond(BcdUtil.readInteger(time, 2));
getLastLocation(position, dateBuilder.getDate());
Network network = new Network();
@@ -593,11 +593,22 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
position.setNetwork(network);
+ if (channel != null) {
+ ByteBuf response = Unpooled.buffer();
+ response.writeShort(0x7878);
+ response.writeByte(0);
+ response.writeByte(type);
+ response.writeBytes(time.resetReaderIndex());
+ response.writeByte('\r');
+ response.writeByte('\n');
+ channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress()));
+ }
+
return position;
}
private Object decodeBasicOther(Channel channel, ByteBuf buf,
- DeviceSession deviceSession, int type, int dataLength) throws Exception {
+ DeviceSession deviceSession, int type, int dataLength) {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
@@ -701,7 +712,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
- private Object decodeExtended(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception {
+ private Object decodeExtended(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
if (deviceSession == null) {
@@ -755,7 +766,9 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
position.set("iccid", ByteBufUtil.hexDump(buf.readSlice(8)));
return position;
} else if (subType == 0x0d) {
- buf.skipBytes(6);
+ if (buf.getByte(buf.readerIndex()) != '!') {
+ buf.skipBytes(6);
+ }
return decodeFuelData(position, buf.toString(
buf.readerIndex(), buf.readableBytes() - 4 - 2, StandardCharsets.US_ASCII));
}
diff --git a/src/org/traccar/protocol/H02ProtocolDecoder.java b/src/org/traccar/protocol/H02ProtocolDecoder.java
index a5f87fe8f..c4443a00b 100644
--- a/src/org/traccar/protocol/H02ProtocolDecoder.java
+++ b/src/org/traccar/protocol/H02ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2019 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.
@@ -163,16 +163,12 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
.expression("..,") // manufacturer
.number("(d+)?,") // imei
.groupBegin()
- .text("VP1,")
- .or()
- .groupBegin()
.text("V4,")
.expression("(.*),") // response
.or()
.expression("(V[^,]*),")
.groupEnd()
.number("(?:(dd)(dd)(dd))?,") // time (hhmmss)
- .groupEnd()
.groupBegin()
.expression("([ABV])?,") // validity
.or()
@@ -268,6 +264,28 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
.text("#").optional()
.compile();
+ private static final Pattern PATTERN_VP1 = new PatternBuilder()
+ .text("*hq,")
+ .number("(d{15}),") // imei
+ .text("VP1,")
+ .groupBegin()
+ .text("V,")
+ .number("(d+),") // mcc
+ .number("(d+),") // mnc
+ .expression("([^#]+)") // cells
+ .or()
+ .expression("[AB],") // validity
+ .number("(d+)(dd.d+),") // latitude
+ .expression("([NS]),")
+ .number("(d+)(dd.d+),") // longitude
+ .expression("([EW]),")
+ .number("(d+.d+),") // speed
+ .number("(d+.d+),") // course
+ .number("(dd)(dd)(dd)") // date (ddmmyy)
+ .groupEnd()
+ .any()
+ .compile();
+
private void sendResponse(Channel channel, SocketAddress remoteAddress, String id, String type) {
if (channel != null && id != null) {
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
@@ -478,6 +496,53 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Position decodeVp1(String sentence, Channel channel, SocketAddress remoteAddress) {
+
+ Parser parser = new Parser(PATTERN_VP1, 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());
+
+ if (parser.hasNext(3)) {
+
+ getLastLocation(position, null);
+
+ int mcc = parser.nextInt();
+ int mnc = parser.nextInt();
+
+ Network network = new Network();
+ for (String cell : parser.next().split("Y")) {
+ String[] values = cell.split(",");
+ network.addCellTower(CellTower.from(mcc, mnc,
+ Integer.parseInt(values[0]), Integer.parseInt(values[1]), Integer.parseInt(values[2])));
+ }
+
+ position.setNetwork(network);
+
+ } else {
+
+ position.setValid(true);
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
+
+ position.setTime(new DateBuilder()
+ .setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)).getDate());
+
+ }
+
+ return position;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -499,6 +564,8 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
return decodeLink(sentence, channel, remoteAddress);
case "V3":
return decodeV3(sentence, channel, remoteAddress);
+ case "VP1":
+ return decodeVp1(sentence, channel, remoteAddress);
default:
return decodeText(sentence, channel, remoteAddress);
}
diff --git a/src/org/traccar/protocol/ItsProtocolDecoder.java b/src/org/traccar/protocol/ItsProtocolDecoder.java
index 000e7759f..62bf1f1e6 100644
--- a/src/org/traccar/protocol/ItsProtocolDecoder.java
+++ b/src/org/traccar/protocol/ItsProtocolDecoder.java
@@ -76,7 +76,7 @@ public class ItsProtocolDecoder extends BaseProtocolDecoder {
String sentence = (String) msg;
if (channel != null && sentence.startsWith("$,01,")) {
- channel.writeAndFlush(new NetworkMessage("$,01,", remoteAddress));
+ channel.writeAndFlush(new NetworkMessage("$,1,*", remoteAddress));
}
Parser parser = new Parser(PATTERN, sentence);
diff --git a/src/org/traccar/protocol/NeosProtocol.java b/src/org/traccar/protocol/NeosProtocol.java
new file mode 100644
index 000000000..e545a9969
--- /dev/null
+++ b/src/org/traccar/protocol/NeosProtocol.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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 io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+
+public class NeosProtocol extends BaseProtocol {
+
+ public NeosProtocol() {
+ addServer(new TrackerServer(true, getName()) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ pipeline.addLast(new StringEncoder());
+ pipeline.addLast(new StringDecoder());
+ pipeline.addLast(new NeosProtocolDecoder(NeosProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/NeosProtocolDecoder.java b/src/org/traccar/protocol/NeosProtocolDecoder.java
new file mode 100644
index 000000000..6b5596dba
--- /dev/null
+++ b/src/org/traccar/protocol/NeosProtocolDecoder.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2019 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 io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.NetworkMessage;
+import org.traccar.Protocol;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+public class NeosProtocolDecoder extends BaseProtocolDecoder {
+
+ public NeosProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text(">")
+ .number("(d{8}),") // id
+ .number("d+,") // status
+ .number("([01]),") // valid
+ .number("(dd)(dd)(dd),") // date (yymmdd)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .expression("([EW])")
+ .number("(d+)(dd.d+),") // longitude
+ .expression("([NS])")
+ .number("(d+)(dd.d+),") // latitude
+ .expression("[^,]*,") // response
+ .number("(d+),") // speed
+ .number("(d+),") // course
+ .number("(d+),") // rssi
+ .expression("[^,]*,") // event data
+ .number("(d+)-") // adc
+ .number("(d+),") // battery
+ .number("0,")
+ .number("d,")
+ .number("([01]{8})") // input
+ .text("*")
+ .number("xx!")
+ .any()
+ .compile();
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ if (channel != null) {
+ channel.writeAndFlush(new NetworkMessage("$OK!", remoteAddress));
+ }
+
+ 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.setValid(parser.nextInt() > 0);
+ position.setTime(parser.nextDateTime());
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN));
+ position.setSpeed(parser.nextInt());
+ position.setCourse(parser.nextInt());
+
+ position.set(Position.KEY_RSSI, parser.nextInt());
+ position.set(Position.PREFIX_ADC + 1, parser.nextInt());
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
+ position.set(Position.KEY_INPUT, parser.nextBinInt());
+
+ return position;
+ }
+
+}
diff --git a/src/org/traccar/protocol/SatsolProtocol.java b/src/org/traccar/protocol/SatsolProtocol.java
new file mode 100644
index 000000000..b69fdd1fe
--- /dev/null
+++ b/src/org/traccar/protocol/SatsolProtocol.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+
+import java.nio.ByteOrder;
+
+public class SatsolProtocol extends BaseProtocol {
+
+ public SatsolProtocol() {
+ addServer(new TrackerServer(false, getName()) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1400, 8, 2, 0, 0, true));
+ pipeline.addLast(new SatsolProtocolDecoder(SatsolProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/SatsolProtocolDecoder.java b/src/org/traccar/protocol/SatsolProtocolDecoder.java
new file mode 100644
index 000000000..77d292d92
--- /dev/null
+++ b/src/org/traccar/protocol/SatsolProtocolDecoder.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2019 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 io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.NetworkMessage;
+import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
+import org.traccar.helper.Checksum;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+public class SatsolProtocolDecoder extends BaseProtocolDecoder {
+
+ public SatsolProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ByteBuf buf = (ByteBuf) msg;
+
+ buf.readUnsignedShortLE(); // checksum
+ buf.readUnsignedShortLE(); // preamble
+ long id = buf.readUnsignedIntLE();
+ buf.readUnsignedShortLE(); // length
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id));
+ if (deviceSession == null) {
+ return null;
+ }
+
+ List<Position> positions = new LinkedList<>();
+
+ while (buf.isReadable()) {
+
+ buf.readUnsignedShortLE(); // checksum
+ buf.readUnsignedShortLE(); // checksum
+ buf.readUnsignedShortLE(); // type
+ int length = buf.readUnsignedShortLE();
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setTime(new Date(buf.readUnsignedIntLE() * 1000));
+ position.setLatitude(buf.readUnsignedIntLE() * 0.000001);
+ position.setLongitude(buf.readUnsignedIntLE() * 0.000001);
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE()));
+ position.setAltitude(buf.readShortLE());
+ position.setCourse(buf.readUnsignedShortLE());
+ position.setValid(buf.readUnsignedByte() > 0);
+
+ position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ position.set(Position.KEY_EVENT, buf.readUnsignedByte());
+
+ if (BitUtil.check(buf.readUnsignedByte(), 0)) {
+ position.set(Position.KEY_ARCHIVE, true);
+ }
+
+ positions.add(position);
+
+ buf.skipBytes(length);
+
+ }
+
+ if (channel != null) {
+ ByteBuf response = Unpooled.buffer();
+ response.writeShortLE(0);
+ response.writeShortLE(0x4CBF); // preamble
+ response.writeIntLE((int) id);
+ response.writeShortLE(0);
+ response.setShortLE(0, Checksum.crc16(
+ Checksum.CRC16_CCITT_FALSE, response.nioBuffer(2, response.readableBytes() - 2)));
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
+ }
+
+ return positions;
+ }
+
+}
diff --git a/src/org/traccar/protocol/TotemProtocolDecoder.java b/src/org/traccar/protocol/TotemProtocolDecoder.java
index ed4c1409a..cd7f684b8 100644
--- a/src/org/traccar/protocol/TotemProtocolDecoder.java
+++ b/src/org/traccar/protocol/TotemProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2019 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.
@@ -150,10 +150,14 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
.number("(dddd)") // adc 4
.groupEnd("?")
.number("(dddd)") // temperature 1
- .number("(dddd)") // temperature 2
+ .number("(dddd)?") // temperature 2
.groupEnd("?")
.number("(xxxx)") // lac
.number("(xxxx)") // cid
+ .groupBegin()
+ .number("(dd)") // mcc
+ .number("(ddd)") // mnc
+ .groupEnd("?")
.number("(dd)") // satellites
.number("(dd)") // gsm (rssi)
.number("(ddd)") // course
@@ -337,29 +341,43 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 18) ? Position.ALARM_LOW_BATTERY : null);
position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 22) ? Position.ALARM_JAMMING : null);
- position.setValid(BitUtil.check(status, 32 - 20));
position.setTime(parser.nextDateTime());
- position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1);
- position.set(Position.KEY_POWER, parser.nextDouble(0));
+ position.set(Position.KEY_BATTERY, parser.nextDouble() * 0.1);
+ position.set(Position.KEY_POWER, parser.nextDouble());
position.set(Position.PREFIX_ADC + 1, parser.next());
position.set(Position.PREFIX_ADC + 2, parser.next());
position.set(Position.PREFIX_ADC + 3, parser.next());
position.set(Position.PREFIX_ADC + 4, parser.next());
position.set(Position.PREFIX_TEMP + 1, parser.next());
- position.set(Position.PREFIX_TEMP + 2, parser.next());
- CellTower cellTower = CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0));
- position.set(Position.KEY_SATELLITES, parser.nextInt(0));
- cellTower.setSignalStrength(parser.nextInt(0));
+ if (parser.hasNext()) {
+ position.set(Position.PREFIX_TEMP + 2, parser.next());
+ position.setValid(BitUtil.check(status, 32 - 20));
+ } else {
+ position.setValid(BitUtil.check(status, 32 - 18));
+ }
+
+ int lac = parser.nextHexInt();
+ int cid = parser.nextHexInt();
+ CellTower cellTower;
+ if (parser.hasNext(2)) {
+ int mnc = parser.nextInt();
+ int mcc = parser.nextInt();
+ cellTower = CellTower.from(mcc, mnc, lac, cid);
+ } else {
+ cellTower = CellTower.fromLacCid(lac, cid);
+ }
+ position.set(Position.KEY_SATELLITES, parser.nextInt());
+ cellTower.setSignalStrength(parser.nextInt());
position.setNetwork(new Network(cellTower));
- position.setCourse(parser.nextDouble(0));
- position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0)));
- position.set(Position.KEY_HDOP, parser.nextDouble(0));
- position.set(Position.KEY_ODOMETER, parser.nextInt(0) * 1000);
+ position.setCourse(parser.nextDouble());
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.set(Position.KEY_HDOP, parser.nextDouble());
+ position.set(Position.KEY_ODOMETER, parser.nextInt() * 1000);
position.setLatitude(parser.nextCoordinate());
position.setLongitude(parser.nextCoordinate());
diff --git a/src/org/traccar/protocol/UproProtocolDecoder.java b/src/org/traccar/protocol/UproProtocolDecoder.java
index c5b72ea0a..dc7a9200d 100644
--- a/src/org/traccar/protocol/UproProtocolDecoder.java
+++ b/src/org/traccar/protocol/UproProtocolDecoder.java
@@ -164,11 +164,13 @@ public class UproProtocolDecoder extends BaseProtocolDecoder {
position.set("statusExtended", data.toString(StandardCharsets.US_ASCII));
break;
case 'P':
- position.setNetwork(new Network(CellTower.from(
- Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)),
- Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)),
- Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII), 16),
- Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII), 16))));
+ if (data.readableBytes() >= 16) {
+ position.setNetwork(new Network(CellTower.from(
+ Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)),
+ Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)),
+ Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII), 16),
+ Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII), 16))));
+ }
break;
case 'Q':
position.set("obdPid", ByteBufUtil.hexDump(data));
diff --git a/src/org/traccar/protocol/VtfmsProtocolDecoder.java b/src/org/traccar/protocol/VtfmsProtocolDecoder.java
index c08261a59..17fac4311 100644
--- a/src/org/traccar/protocol/VtfmsProtocolDecoder.java
+++ b/src/org/traccar/protocol/VtfmsProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2019 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.
@@ -60,7 +60,7 @@ public class VtfmsProtocolDecoder extends BaseProtocolDecoder {
.number("(d+.d+),") // power voltage
.number("[^,]*,") // reserved
.number("(d+)?,") // fuel level
- .number("(d+.d+),") // adc 1
+ .number("(d+.d+)?,") // adc 1
.number("[^,]*,") // reserved
.number("(d+.d+)?,") // adc 2
.expression("([01]),") // di 1
@@ -93,6 +93,11 @@ public class VtfmsProtocolDecoder extends BaseProtocolDecoder {
}
}
+ private double convertToDegrees(double value) {
+ double degrees = Math.floor(value / 100);
+ return degrees + (value - degrees * 100) / 60;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -116,12 +121,18 @@ public class VtfmsProtocolDecoder extends BaseProtocolDecoder {
position.setValid(parser.next().equals("A"));
position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY));
- position.setLatitude(parser.nextDouble(0));
- position.setLongitude(parser.nextDouble(0));
- if (parser.hasNext()) {
- position.setCourse(parser.nextDouble(0));
+ double latitude = parser.nextDouble();
+ double longitude = parser.nextDouble();
+ if (Math.abs(latitude) > 90 || Math.abs(longitude) > 180) {
+ position.setLatitude(convertToDegrees(latitude));
+ position.setLongitude(convertToDegrees(longitude));
+ } else {
+ position.setLatitude(latitude);
+ position.setLongitude(longitude);
}
+
+ position.setCourse(parser.nextDouble(0));
if (parser.hasNext()) {
String direction = parser.next();
for (int i = 0; i < DIRECTIONS.length; i++) {
@@ -132,7 +143,7 @@ public class VtfmsProtocolDecoder extends BaseProtocolDecoder {
}
}
- position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0)));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(parser.nextInt()));
position.set("idleHours", parser.nextInt());