aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--setup/default.xml2
-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
-rw-r--r--test/org/traccar/protocol/CellocatorProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/EelinkProtocolDecoderTest.java5
-rw-r--r--test/org/traccar/protocol/Gps103ProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/Gt06ProtocolDecoderTest.java9
-rw-r--r--test/org/traccar/protocol/H02ProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/NeosProtocolDecoderTest.java18
-rw-r--r--test/org/traccar/protocol/SatsolProtocolDecoderTest.java18
-rw-r--r--test/org/traccar/protocol/T55ProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/TotemProtocolDecoderTest.java7
-rw-r--r--test/org/traccar/protocol/UproProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/VtfmsProtocolDecoderTest.java4
28 files changed, 675 insertions, 120 deletions
diff --git a/setup/default.xml b/setup/default.xml
index f0aecddb4..7662e286a 100644
--- a/setup/default.xml
+++ b/setup/default.xml
@@ -259,5 +259,7 @@
<entry key='xrb28.port'>5180</entry>
<entry key='c2stek.port'>5181</entry>
<entry key='nyitech.port'>5182</entry>
+ <entry key='neos.port'>5183</entry>
+ <entry key='satsol.port'>5184</entry>
</properties>
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());
diff --git a/test/org/traccar/protocol/CellocatorProtocolDecoderTest.java b/test/org/traccar/protocol/CellocatorProtocolDecoderTest.java
index 602cd4eac..769760fa5 100644
--- a/test/org/traccar/protocol/CellocatorProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/CellocatorProtocolDecoderTest.java
@@ -11,6 +11,9 @@ public class CellocatorProtocolDecoderTest extends ProtocolTest {
CellocatorProtocolDecoder decoder = new CellocatorProtocolDecoder(null);
verifyPosition(decoder, binary(
+ "4d4350470041420f000402021226d8a70221d801010000000001000000000000000000000000c4d90000000ca7a741ff0096dd15a40700000000000000001619130c01e307e4"));
+
+ verifyPosition(decoder, binary(
"4D434750008AD01500080103011804000000460020000000005E750000000000000000000000C34300040204DA4DA30367195703E803000000000000000001030F0802E10778"));
verifyPosition(decoder, binary(
diff --git a/test/org/traccar/protocol/EelinkProtocolDecoderTest.java b/test/org/traccar/protocol/EelinkProtocolDecoderTest.java
index 921b9e327..3e2a896f7 100644
--- a/test/org/traccar/protocol/EelinkProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/EelinkProtocolDecoderTest.java
@@ -2,6 +2,7 @@ package org.traccar.protocol;
import org.junit.Test;
import org.traccar.ProtocolTest;
+import org.traccar.model.Position;
public class EelinkProtocolDecoderTest extends ProtocolTest {
@@ -13,6 +14,10 @@ public class EelinkProtocolDecoderTest extends ProtocolTest {
verifyNull(decoder, binary(
"454C0027E753035254407167747167670100180002035254407167747100200205020500010432000086BD"));
+ verifyAttribute(decoder, binary(
+ "6767120043000e5c37387c0304e4e1b4f8194fa800160013009408012e03702d8706453c6e5b066f115f05710000001b067f8d248d240313020500000000000000000000000001cc"),
+ Position.PREFIX_TEMP + 2, 28.75);
+
verifyPosition(decoder, binary(
"676714002414B05AD43A7D03026B92B10C395499FFD7000000000701CC00002495000014203604067B"));
diff --git a/test/org/traccar/protocol/Gps103ProtocolDecoderTest.java b/test/org/traccar/protocol/Gps103ProtocolDecoderTest.java
index 00e85f5e3..b44eb26f9 100644
--- a/test/org/traccar/protocol/Gps103ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/Gps103ProtocolDecoderTest.java
@@ -12,6 +12,12 @@ public class Gps103ProtocolDecoderTest extends ProtocolTest {
Gps103ProtocolDecoder decoder = new Gps103ProtocolDecoder(null);
verifyPosition(decoder, text(
+ "imei:864180034124375,vt14,190116192753,,F,172750.000,A,3649.2186,N,00235.8411,W,0.00,0,,0,0,51.93%,,+22;"));
+
+ verifyNull(decoder, text(
+ "imei:864180034124375,vr,0c00fa011ea05a03d726977103ad0034c98ef49e6d303fffd1c8361303f2dbb0fa530d8ca3930be3e94f4110145c7029a507a0a00028f4a70514c05c500503170334b400531971cad002ab7634f001a4027949c8e541ea47f853bca2f961ba427ab1e290089197711c485e4f6e82ad0d1ee8f25573eed4af60284f6935bb7ef2307f1dc3f4355bbf3f90a607ffd2e5fcc6c60310be80f152dbca54ed53147fed3ae7fa1fe54809e45330fdedc993d073b7f2a6340a00d8cabeb9a4980c68900e5cb1f6e29aab9e00fc334012a5a5c32e5227c7b21a9a2d35dc02cdb49edb189fe545ec058fec7565e667cfa08b1fccd34686e4f12003dd7ffaf4b980957440bd595beb53269bb082a517dd570693604cb6299cb1663f5a9d608e3e42807d71cd002d206028011e50aa49381513494011349cd2092803ffd3d031f154ef11bc86d870781f8679a90302540adc545c55a00e28c8a602e47ad2e46680133cd19e6800cd1cf4a0063293ce695188e0d20265e58559305c3ffcb2948eca10d20278adb50518890c40f5ed9a5fece941ccb29cfd19ff00c2a6e860d6471c7da1cffb3b507eb9aaafa3dc4a4909b7fdf6c9fd28b88fffd4ca5d06e7b94152af87a53f7a7403d949a8e60265f0eaff0014ee7e8807f5a99340857abcadf881fd2973013a6936f1f48d4ffbc01fe95652dd63fba00fa521926d1de8e07a51600dc3d01d00;"));
+
+ verifyPosition(decoder, text(
"imei:868683026321020,T:+11,181217080050,,F,080047.000,A,3227.3057,N,11649.4754,W,0.00,0,,0,0,0.00%,,+11;"));
verifyAttribute(decoder, text(
diff --git a/test/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/test/org/traccar/protocol/Gt06ProtocolDecoderTest.java
index 8b7034ca8..570cd7506 100644
--- a/test/org/traccar/protocol/Gt06ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/Gt06ProtocolDecoderTest.java
@@ -16,6 +16,12 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
verifyNull(decoder, binary(
"78780D01086471700328358100093F040D0A"));
+ verifyNotNull(decoder, binary(
+ "7878006919012105090303028f01007549e05a00bc9c5c5a007a8d1a5a0d0a"));
+
+ verifyNotNull(decoder, binary(
+ "7878001719011910543607028f0100bc2e695a00bcb3635a00bc27c56400bc447b6400bc46c96400bc33ce6400bc64ca640d0a"));
+
verifyAttributes(decoder, binary(
"797900de8c120b1502121b013137333d302c3232333d312c3238333d30303030303030302c3436333d30303030303035362c3437333d30303030303030662c3438333d30303030303031312c3242333d30303030303030302c3244333d30303030313839632c3335333d30303030313661382c3336333d30303032386163382c3339333d30303030303230612c3330333d30303030303561612c3439333d30303030303030302c3441333d4b4e4146323431434d4b353031343235352c3341333d30303030303338352c3530333d30303030c0041df0940f89c06700000000c800910d0a"));
@@ -172,6 +178,9 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
verifyAttributes(decoder, binary(
"7979003F940D110315102A202141494F494C2C30322C3030382E3239302C3032392E3630302C3531394A2C303430302C3030382E3433302C302C30302C4142001678EA0D0A"));
+ verifyAttributes(decoder, binary(
+ "79790039940d2141494f494c2c30322c3030322e3732302c3032392e3530302c3532344a2c303130302c3030332e3430302c302c30302c393309ad72000d0a"));
+
verifyNull(decoder, binary(
"79790005840016BB1A0D0A"));
diff --git a/test/org/traccar/protocol/H02ProtocolDecoderTest.java b/test/org/traccar/protocol/H02ProtocolDecoderTest.java
index acfb96c82..4a5eadf52 100644
--- a/test/org/traccar/protocol/H02ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/H02ProtocolDecoderTest.java
@@ -11,6 +11,9 @@ public class H02ProtocolDecoderTest extends ProtocolTest {
H02ProtocolDecoder decoder = new H02ProtocolDecoder(null);
+ verifyNotNull(decoder, buffer(
+ "*hq,356327081001239,VP1,V,470,002,92,3565,0Y92,19433,30Y92,1340,29#"));
+
verifyPosition(decoder, binary(
"2435248308419329301047591808172627335900074412294E024138FEFFFFFFFF01120064BA73005ECC"));
diff --git a/test/org/traccar/protocol/NeosProtocolDecoderTest.java b/test/org/traccar/protocol/NeosProtocolDecoderTest.java
new file mode 100644
index 000000000..a8db30476
--- /dev/null
+++ b/test/org/traccar/protocol/NeosProtocolDecoderTest.java
@@ -0,0 +1,18 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class NeosProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ NeosProtocolDecoder decoder = new NeosProtocolDecoder(null);
+
+ verifyPosition(decoder, text(
+ ">12345678,1,1,070201,144111,W05829.2613,S3435.2313,,00,034,25,00,126-000,0,3,11111111*2d!\r\n"));
+
+ }
+
+}
diff --git a/test/org/traccar/protocol/SatsolProtocolDecoderTest.java b/test/org/traccar/protocol/SatsolProtocolDecoderTest.java
new file mode 100644
index 000000000..acdb5a084
--- /dev/null
+++ b/test/org/traccar/protocol/SatsolProtocolDecoderTest.java
@@ -0,0 +1,18 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class SatsolProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ SatsolProtocolDecoder decoder = new SatsolProtocolDecoder(null);
+
+ verifyPositions(decoder, binary(
+ "22b5bf4cb2ec1600500122b37ba020001500cb5d2f5c68c24a0310aecd016200b1003d000004000177042700a501000000000000000101020100011e00a1657ca020001500cf5d2f5c68c24a03dbadcd013501b10097000004030177042700a501000000000000000101020101011e00816e7da003004800b95e2f5c89c24a03fbadcd010000aa00000000040601011038363133353930333632333039323600383933373530323730313030323335343836363000323537303237303132333534383636004d5453000000000066640101005700e515cf047ea001000000295f2f5c89c24a03fbadcd0100009a0000000106020106dc30a8030048006bc13e5c19c24a03bfadcd010000ad00000000050600011338363133353930333632333039323600383933373530323730313030323335343836363000323537303237303132333534383636004d5453000000000066640101005700e515"));
+
+ }
+
+}
diff --git a/test/org/traccar/protocol/T55ProtocolDecoderTest.java b/test/org/traccar/protocol/T55ProtocolDecoderTest.java
index 6b286b485..c5737f367 100644
--- a/test/org/traccar/protocol/T55ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/T55ProtocolDecoderTest.java
@@ -10,6 +10,9 @@ public class T55ProtocolDecoderTest extends ProtocolTest {
T55ProtocolDecoder decoder = new T55ProtocolDecoder(null);
+ verifyPosition(decoder, text(
+ "660420156A0066AA$GPRMC,122806.0,A,0119.212178,N,10355.000942,E,0.0,,230119,0.0,E,A*27"));
+
verifyNull(decoder, text(
"$IMEI=355797031609284"));
diff --git a/test/org/traccar/protocol/TotemProtocolDecoderTest.java b/test/org/traccar/protocol/TotemProtocolDecoderTest.java
index c9990acdf..287c54968 100644
--- a/test/org/traccar/protocol/TotemProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/TotemProtocolDecoderTest.java
@@ -11,6 +11,10 @@ public class TotemProtocolDecoderTest extends ProtocolTest {
TotemProtocolDecoder decoder = new TotemProtocolDecoder(null);
verifyPosition(decoder, text(
+ "$$0113AA862010037348253|588040001901220851494212000000753AE901655121700100000.800000002632.6084S02803.3289E29497E"),
+ position("2019-01-22 08:51:49.000", true, -26.54347, 28.05548));
+
+ verifyPosition(decoder, text(
"$$011602867119025755430|50099800180420045019401400000000000000B8797D110816811201.500002132615.7037S02801.8099E056149"));
verifyPosition(decoder, text(
@@ -32,7 +36,8 @@ public class TotemProtocolDecoderTest extends ProtocolTest {
"$$0128AA864244026065291|18001800140916020524401100000000000000000000000027BA0E57063100000001.200000002237.8119N11403.5075E05202D"));
verifyPosition(decoder, text(
- "$$0128AA867965024919124|10010800160223032415401203270321032103270189000027BA0E4E001800200001.000000002237.7581N11403.5088E000957"));
+ "$$0128AA867965024919124|10010800160223032415401203270321032103270189000027BA0E4E001800200001.000000002237.7581N11403.5088E000957"),
+ position("2016-02-23 03:24:15.000", false, 22.62930, 114.05848));
verifyPosition(decoder, text(
"$$0108AA863835024426319|18004000160216160756411100007DCD0000111000000000.800000000316.3519N10228.5086E126522"));
diff --git a/test/org/traccar/protocol/UproProtocolDecoderTest.java b/test/org/traccar/protocol/UproProtocolDecoderTest.java
index ff7ead961..dbbe4591f 100644
--- a/test/org/traccar/protocol/UproProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/UproProtocolDecoderTest.java
@@ -11,6 +11,9 @@ public class UproProtocolDecoderTest extends ProtocolTest {
UproProtocolDecoder decoder = new UproProtocolDecoder(null);
verifyPosition(decoder, buffer(
+ "*HQ200861810538000002,BA&A0206033302618209658563620115180119&B0100000040&C6328680=&F0039&R2710&V0036&T09&K50000&N04&P0200#"));
+
+ verifyPosition(decoder, buffer(
"*HQ200999999,AB1&A1656512233362911356523660000230618&B0100060010&C00000<6<&F0000&R2405&V0109&W0000003E&K00100&T65&X(k89860045191536000374)#"));
verifyPosition(decoder, buffer(
diff --git a/test/org/traccar/protocol/VtfmsProtocolDecoderTest.java b/test/org/traccar/protocol/VtfmsProtocolDecoderTest.java
index 2d3940528..ede5dc7ac 100644
--- a/test/org/traccar/protocol/VtfmsProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/VtfmsProtocolDecoderTest.java
@@ -11,6 +11,10 @@ public class VtfmsProtocolDecoderTest extends ProtocolTest {
VtfmsProtocolDecoder decoder = new VtfmsProtocolDecoder(null);
verifyPosition(decoder, text(
+ "(861359037432331,0EF87,00,0,21,2,01,,A,154559,230119,1101.4046,07656.3859,241,000,00078,00000,K,0000812,1,12.7,,,,,,1,0,0,0,1,1,1,+919566531111*+919994462226,)054"),
+ position("2019-01-23 15:45:59.000", true, 11.02341, 76.93977));
+
+ verifyPosition(decoder, text(
"(865733028143493,00I76,00,000,,,,,A,133755,210617,10.57354,077.24912,SW,000,00598,00000,K,0017368,1,12.7,,,0.000,,,0,0,0,0,1,1,0,,)074"));
verifyPosition(decoder, text(