diff options
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( |