From 2e0ed3ccfde8f779111de2b722a94224faa65c99 Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Tue, 11 Jul 2017 15:57:20 +0300 Subject: Create duplicate of ARNAVI3 protocol implementation. Add an entry with ARNAVI4 port to the properties in default.xml. --- setup/default.xml | 1 + src/org/traccar/protocol/Arnavi4Protocol.java | 35 +++++++++ .../traccar/protocol/Arnavi4ProtocolDecoder.java | 87 ++++++++++++++++++++++ .../protocol/Arnavi4ProtocolDecoderTest.java | 26 +++++++ 4 files changed, 149 insertions(+) create mode 100644 src/org/traccar/protocol/Arnavi4Protocol.java create mode 100644 src/org/traccar/protocol/Arnavi4ProtocolDecoder.java create mode 100644 test/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java diff --git a/setup/default.xml b/setup/default.xml index 2fc6c3cf0..223b9a585 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -579,5 +579,6 @@ 5143 5144 5145 + 5146 diff --git a/src/org/traccar/protocol/Arnavi4Protocol.java b/src/org/traccar/protocol/Arnavi4Protocol.java new file mode 100644 index 000000000..622051fbd --- /dev/null +++ b/src/org/traccar/protocol/Arnavi4Protocol.java @@ -0,0 +1,35 @@ +package org.traccar.protocol; + +import org.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.handler.codec.frame.LineBasedFrameDecoder; +import org.jboss.netty.handler.codec.string.StringDecoder; +import org.jboss.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.TrackerServer; + +import java.util.List; + +/** + * Created by Ivan Muratov @binakot on 11.07.2017. + */ +public class Arnavi4Protocol extends BaseProtocol { + + public Arnavi4Protocol() { + super("arnavi4"); + } + + @Override + public void initTrackerServers(List serverList) { + serverList.add(new TrackerServer(new ServerBootstrap(), getName()) { + @Override + protected void addSpecificHandlers(ChannelPipeline pipeline) { + pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024)); + pipeline.addLast("stringDecoder", new StringDecoder()); + pipeline.addLast("stringEncoder", new StringEncoder()); + pipeline.addLast("objectDecoder", new Arnavi4ProtocolDecoder(Arnavi4Protocol.this)); + } + }); + } + +} diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java new file mode 100644 index 000000000..dbedff9a1 --- /dev/null +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -0,0 +1,87 @@ +package org.traccar.protocol; + +import org.jboss.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +/** + * Created by Ivan Muratov @binakot on 11.07.2017. + */ +public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { + + public Arnavi4ProtocolDecoder(Arnavi4Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$AV,") + .number("Vd,") // type + .number("(d+),") // device id + .number("(d+),") // index + .number("(d+),") // power + .number("(d+),") // battery + .number("-?d+,") + .expression("[01],") // movement + .expression("([01]),") // ignition + .number("(d+),") // input + .number("d+,d+,") // input 1 + .number("d+,d+,").optional() // input 2 + .expression("[01],") // fix type + .number("(d+),") // satellites + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(dd)(dd.d+)([NS]),") // latitude + .number("(ddd)(dd.d+)([EW]),") // longitude + .number("(d+.d+),") // speed + .number("(d+.d+),") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(); + position.setProtocol(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_INDEX, parser.nextInt(0)); + position.set(Position.KEY_POWER, parser.nextInt(0) * 0.01); + position.set(Position.KEY_BATTERY, parser.nextInt(0) * 0.01); + position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); + position.set(Position.KEY_INPUT, parser.nextInt(0)); + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(true); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + return position; + } + +} diff --git a/test/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java b/test/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java new file mode 100644 index 000000000..b199fe565 --- /dev/null +++ b/test/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java @@ -0,0 +1,26 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.*; + +/** + * Created by Ivan Muratov @binakot on 11.07.2017. + */ +public class Arnavi4ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Arnavi4ProtocolDecoder decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); + + verifyPosition(decoder, text( + "$AV,V2,32768,12487,2277,203,-1,0,0,193,0,0,1,13,200741,5950.6773N,03029.1043E,0.0,0.0,121012,*6E")); + + verifyPosition(decoder, text( + "$AV,V3,999999,12487,2277,203,65534,0,0,193,65535,65535,65535,65535,1,13,200741,5950.6773N,03029.1043E,300.0,360.0,121012,65535,65535,65535,SF*6E")); + + } + +} -- cgit v1.2.3 From 6e70a873886b366980423e448808b60c624e4047 Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Thu, 13 Jul 2017 08:30:35 +0300 Subject: Basic ARNAVI4 binary protocol implementation is done. Supported 2 types of HEADER packets (v1, v2). Supported 3 types of PACKAGE DATA records: latitude, longitude and additional data (speed, satellites, altitude, course). --- src/org/traccar/protocol/Arnavi4FrameDecoder.java | 51 ++++++ src/org/traccar/protocol/Arnavi4Protocol.java | 14 +- .../traccar/protocol/Arnavi4ProtocolDecoder.java | 188 +++++++++++++++------ .../traccar/protocol/Arnavi4FrameDecoderTest.java | 37 ++++ .../protocol/Arnavi4ProtocolDecoderTest.java | 23 ++- 5 files changed, 249 insertions(+), 64 deletions(-) create mode 100644 src/org/traccar/protocol/Arnavi4FrameDecoder.java create mode 100644 test/org/traccar/protocol/Arnavi4FrameDecoderTest.java diff --git a/src/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/org/traccar/protocol/Arnavi4FrameDecoder.java new file mode 100644 index 000000000..eaf829cc3 --- /dev/null +++ b/src/org/traccar/protocol/Arnavi4FrameDecoder.java @@ -0,0 +1,51 @@ +package org.traccar.protocol; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.handler.codec.frame.FrameDecoder; + +/** + * Created by Ivan Muratov @binakot on 12.07.2017. + */ +public class Arnavi4FrameDecoder extends FrameDecoder { + + static final byte HEADER_START_SIGN = (byte)0xFF; + static final byte HEADER_VERSION_1 = 0x22; + static final byte HEADER_VERSION_2 = 0x23; + static final int HEADER_LENGTH = 10; + + static final byte PACKAGE_START_SIGN = 0x5B; + static final byte PACKAGE_END_SIGN = 0x5D; + static final int PACKAGE_MIN_PARCEL_NUMBER = 0x01; + static final int PACKAGE_MAX_PARCEL_NUMBER = 0xFB; + + @Override + protected Object decode( + ChannelHandlerContext ctx, + Channel channel, + ChannelBuffer buf) throws Exception { + + if (buf.readableBytes() == 0) { + return null; + } + + byte[] bytes = new byte[buf.readableBytes()]; + buf.getBytes(0, bytes); + + if (bytes[0] == HEADER_START_SIGN + && bytes.length == HEADER_LENGTH + && (bytes[1] == HEADER_VERSION_1 || bytes[1] == HEADER_VERSION_2)) { + return buf.readBytes(HEADER_LENGTH); + } + + int parcelNumber = bytes[1] & 0xFF; + if (bytes[0] == PACKAGE_START_SIGN && bytes[bytes.length - 1] == PACKAGE_END_SIGN + && parcelNumber >= PACKAGE_MIN_PARCEL_NUMBER && parcelNumber <= PACKAGE_MAX_PARCEL_NUMBER) { + return buf.readBytes(bytes.length); + } + + return null; + } + +} diff --git a/src/org/traccar/protocol/Arnavi4Protocol.java b/src/org/traccar/protocol/Arnavi4Protocol.java index 622051fbd..227397980 100644 --- a/src/org/traccar/protocol/Arnavi4Protocol.java +++ b/src/org/traccar/protocol/Arnavi4Protocol.java @@ -2,12 +2,10 @@ package org.traccar.protocol; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelPipeline; -import org.jboss.netty.handler.codec.frame.LineBasedFrameDecoder; -import org.jboss.netty.handler.codec.string.StringDecoder; -import org.jboss.netty.handler.codec.string.StringEncoder; import org.traccar.BaseProtocol; import org.traccar.TrackerServer; +import java.nio.ByteOrder; import java.util.List; /** @@ -21,15 +19,15 @@ public class Arnavi4Protocol extends BaseProtocol { @Override public void initTrackerServers(List serverList) { - serverList.add(new TrackerServer(new ServerBootstrap(), getName()) { + TrackerServer server = new TrackerServer(new ServerBootstrap(), getName()) { @Override protected void addSpecificHandlers(ChannelPipeline pipeline) { - pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024)); - pipeline.addLast("stringDecoder", new StringDecoder()); - pipeline.addLast("stringEncoder", new StringEncoder()); + pipeline.addLast("frameDecoder", new Arnavi4FrameDecoder()); pipeline.addLast("objectDecoder", new Arnavi4ProtocolDecoder(Arnavi4Protocol.this)); } - }); + }; + server.setEndianness(ByteOrder.LITTLE_ENDIAN); + serverList.add(server); } } diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index dbedff9a1..caa8dd28f 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -1,87 +1,175 @@ package org.traccar.protocol; +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.DeviceSession; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; import org.traccar.model.Position; import java.net.SocketAddress; -import java.util.regex.Pattern; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +import static org.traccar.protocol.Arnavi4FrameDecoder.*; /** * Created by Ivan Muratov @binakot on 11.07.2017. */ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { + private static final byte RECORD_PING = 0x00; + private static final byte RECORD_DATA = 0x01; + private static final byte RECORD_TEXT = 0x03; + private static final byte RECORD_FILE = 0x04; + private static final byte RECORD_BINARY = 0x06; + + private static final byte TAG_LATITUDE = 3; + private static final byte TAG_LONGITUDE = 4; + private static final byte TAG_COORD_PARAMS = 5; + public Arnavi4ProtocolDecoder(Arnavi4Protocol protocol) { super(protocol); } - private static final Pattern PATTERN = new PatternBuilder() - .text("$AV,") - .number("Vd,") // type - .number("(d+),") // device id - .number("(d+),") // index - .number("(d+),") // power - .number("(d+),") // battery - .number("-?d+,") - .expression("[01],") // movement - .expression("([01]),") // ignition - .number("(d+),") // input - .number("d+,d+,") // input 1 - .number("d+,d+,").optional() // input 2 - .expression("[01],") // fix type - .number("(d+),") // satellites - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(dd)(dd.d+)([NS]),") // latitude - .number("(ddd)(dd.d+)([EW]),") // longitude - .number("(d+.d+),") // speed - .number("(d+.d+),") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .any() - .compile(); + private static int modulo256Checksum(byte[] bytes) { + int sum = 0; + for (byte b : bytes) { + sum = (sum + b) & 0xFF; + } + return sum; + } + + private Position decodePosition(DeviceSession deviceSession, ChannelBuffer buf, long timestamp) { + + final Position position = new Position(); + position.setProtocol(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date(timestamp)); + + while (buf.readableBytes() > 0) { + short tagId = buf.readUnsignedByte(); + int tagValue = buf.readInt(); + switch (tagId) { + case TAG_LATITUDE: + position.setLatitude(Float.intBitsToFloat(tagValue)); + position.setValid(true); + break; + + case TAG_LONGITUDE: + position.setLongitude(Float.intBitsToFloat(tagValue)); + position.setValid(true); + break; + + case TAG_COORD_PARAMS: + position.setSpeed((tagValue >> 24) * 1.852); + position.set(Position.KEY_SATELLITES, (tagValue >> 16 & 0x0F) + (tagValue >> 20 & 0x0F)); + position.setAltitude((tagValue >> 8 & 0xFF) * 10.0); + position.setCourse((tagValue & 0xFF) * 2.0); + break; + + default: + break; // Skip other tags + } + } + + return position; + } @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { + ChannelBuffer buf = (ChannelBuffer) msg; + + byte startSign = buf.readByte(); + + if (startSign == HEADER_START_SIGN) { + + byte version = buf.readByte(); + + String imei = String.valueOf(buf.readLong()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + + if (deviceSession != null && channel != null) { + + final ChannelBuffer response; + + if (version == HEADER_VERSION_1) { + response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 4); + response.writeBytes(new byte[]{0x7B, 0x00, 0x00, 0x7D}); + + } else if (version == HEADER_VERSION_2) { + response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 9); + response.writeBytes(new byte[]{0x7B, 0x04, 0x00}); + byte[] timestampBytes = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)).array(); + response.writeByte(modulo256Checksum(timestampBytes)); + response.writeBytes(timestampBytes); + response.writeByte(0x7D); + + } else { + throw new IllegalArgumentException("unsupported header version"); + } + + channel.write(response); + } + return null; } - Position position = new Position(); - position.setProtocol(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); if (deviceSession == null) { return null; } - position.setDeviceId(deviceSession.getDeviceId()); - position.set(Position.KEY_INDEX, parser.nextInt(0)); - position.set(Position.KEY_POWER, parser.nextInt(0) * 0.01); - position.set(Position.KEY_BATTERY, parser.nextInt(0) * 0.01); - position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); - position.set(Position.KEY_INPUT, parser.nextInt(0)); - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + if (startSign == PACKAGE_START_SIGN) { - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + List positions = new LinkedList<>(); - position.setValid(true); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); + int parcelNumber = buf.readUnsignedByte(); - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); + byte recordStartSign = buf.readByte(); + while (recordStartSign != PACKAGE_END_SIGN) { + switch (recordStartSign) { + case RECORD_PING: + case RECORD_DATA: + case RECORD_TEXT: + case RECORD_FILE: + case RECORD_BINARY: { + int length = buf.readUnsignedShort(); + long timestamp = buf.readUnsignedInt() * 1000; + ChannelBuffer recordBuf = buf.readBytes(length); - return position; + if (recordStartSign == RECORD_DATA) { + positions.add(decodePosition(deviceSession, recordBuf, timestamp)); + } + + buf.readUnsignedByte(); // crc + + break; + } + + default: + throw new IllegalArgumentException("unsupported record type"); + } + + recordStartSign = buf.readByte(); + } + + if (channel != null) { + final ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 4); + response.writeBytes(new byte[]{0x7B, 0x00, (byte) parcelNumber, 0x7D}); + channel.write(response); + } + + return positions; + } + + return null; } } diff --git a/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java b/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java new file mode 100644 index 000000000..08abd3835 --- /dev/null +++ b/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java @@ -0,0 +1,37 @@ +package org.traccar.protocol; + +import org.junit.Assert; +import org.junit.Test; +import org.traccar.ProtocolTest; + +import java.nio.ByteOrder; + +/** + * Created by Ivan Muratov @binakot on 13.07.2017. + */ +public class Arnavi4FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Arnavi4FrameDecoder decoder = new Arnavi4FrameDecoder(); + + Assert.assertEquals( // Valid HEADER v1 packet with IMEI + binary(ByteOrder.LITTLE_ENDIAN, "ff22f30c45f5c90f0300"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "ff22f30c45f5c90f0300"))); + + Assert.assertEquals( // Valid HEADER v2 packet with IMEI + binary(ByteOrder.LITTLE_ENDIAN, "ff23f30c45f5c90f0300"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "ff23f30c45f5c90f0300"))); + + Assert.assertEquals( // Valid PACKAGE packet with one DATA packet + binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); + + Assert.assertEquals( // Valid PACKAGE packet with two DATA packet + binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); + + } + +} \ No newline at end of file diff --git a/test/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java b/test/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java index b199fe565..2395572a1 100644 --- a/test/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java @@ -3,7 +3,7 @@ package org.traccar.protocol; import org.junit.Test; import org.traccar.ProtocolTest; -import static org.junit.Assert.*; +import java.nio.ByteOrder; /** * Created by Ivan Muratov @binakot on 11.07.2017. @@ -13,14 +13,25 @@ public class Arnavi4ProtocolDecoderTest extends ProtocolTest { @Test public void testDecode() throws Exception { - Arnavi4ProtocolDecoder decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); + Arnavi4ProtocolDecoder decoder; - verifyPosition(decoder, text( - "$AV,V2,32768,12487,2277,203,-1,0,0,193,0,0,1,13,200741,5950.6773N,03029.1043E,0.0,0.0,121012,*6E")); + decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); - verifyPosition(decoder, text( - "$AV,V3,999999,12487,2277,203,65534,0,0,193,65535,65535,65535,65535,1,13,200741,5950.6773N,03029.1043E,300.0,360.0,121012,65535,65535,65535,SF*6E")); + verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid HEADER v1 packet with IMEI + "ff22f30c45f5c90f0300")); + verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid PACKAGE packet with one DATA packet + "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); + + decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); + + verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid HEADER v2 packet with IMEI + "ff23f30c45f5c90f0300")); + + verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid PACKAGE packet with two DATA packet + "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); } } -- cgit v1.2.3 From 358b591bc457786927ac1466e10181bbffbcf56b Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Thu, 13 Jul 2017 08:42:17 +0300 Subject: Replace MODULO256 checksum method. Added covering tests. --- src/org/traccar/helper/Checksum.java | 8 ++++++++ src/org/traccar/protocol/Arnavi4ProtocolDecoder.java | 11 ++--------- test/org/traccar/helper/ChecksumTest.java | 8 ++++++++ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/org/traccar/helper/Checksum.java b/src/org/traccar/helper/Checksum.java index 43ba6a689..7a0151d36 100644 --- a/src/org/traccar/helper/Checksum.java +++ b/src/org/traccar/helper/Checksum.java @@ -243,4 +243,12 @@ public final class Checksum { return (10 - (checksum % 10)) % 10; } + public static int modulo256(byte... bytes) { + int sum = 0; + for (byte b : bytes) { + sum = (sum + b) & 0xFF; + } + return sum; + } + } diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index caa8dd28f..46caebb71 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -5,6 +5,7 @@ import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.DeviceSession; +import org.traccar.helper.Checksum; import org.traccar.model.Position; import java.net.SocketAddress; @@ -35,14 +36,6 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { super(protocol); } - private static int modulo256Checksum(byte[] bytes) { - int sum = 0; - for (byte b : bytes) { - sum = (sum + b) & 0xFF; - } - return sum; - } - private Position decodePosition(DeviceSession deviceSession, ChannelBuffer buf, long timestamp) { final Position position = new Position(); @@ -107,7 +100,7 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 9); response.writeBytes(new byte[]{0x7B, 0x04, 0x00}); byte[] timestampBytes = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)).array(); - response.writeByte(modulo256Checksum(timestampBytes)); + response.writeByte(Checksum.modulo256(timestampBytes)); response.writeBytes(timestampBytes); response.writeByte(0x7D); diff --git a/test/org/traccar/helper/ChecksumTest.java b/test/org/traccar/helper/ChecksumTest.java index c37eda88d..737b65c62 100644 --- a/test/org/traccar/helper/ChecksumTest.java +++ b/test/org/traccar/helper/ChecksumTest.java @@ -4,6 +4,7 @@ import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.junit.Assert; import org.junit.Test; +import org.traccar.protocol.Arnavi4ProtocolDecoder; import java.nio.charset.StandardCharsets; @@ -28,4 +29,11 @@ public class ChecksumTest { Assert.assertEquals(0, Checksum.luhn(63070019470771L)); } + @Test + public void testModulo256() { + Assert.assertEquals(0x00, Checksum.modulo256((byte)0x00)); + Assert.assertEquals(0x00, Checksum.modulo256((byte)0x00, (byte)0x00, (byte)0x00)); + Assert.assertEquals(0x06, Checksum.modulo256((byte)0x01, (byte)0x02, (byte)0x03)); + } + } -- cgit v1.2.3 From f643173b6b2c52a3896d6ee13578edd86f9eb3e7 Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Thu, 13 Jul 2017 09:10:57 +0300 Subject: Fix build issues. [ERROR] src/org/traccar/protocol/Arnavi4FrameDecoder.java:[13,49] (whitespace) WhitespaceAfter: 'typecast' is not followed by whitespace. [ERROR] src/org/traccar/protocol/Arnavi4ProtocolDecoder.java:[18] (imports) AvoidStarImport: Using the '.*' form of import should be avoided - org.traccar.protocol.Arnavi4FrameDecoder.*. [ERROR] src/org/traccar/protocol/Arnavi4ProtocolDecoder.java:[102] (sizes) LineLength: Line is longer than 120 characters (found 125). [ERROR] src/org/traccar/protocol/Arnavi4ProtocolDecoder.java:[135,41] (blocks) AvoidNestedBlocks: Avoid nested blocks. --- src/org/traccar/protocol/Arnavi4FrameDecoder.java | 2 +- src/org/traccar/protocol/Arnavi4ProtocolDecoder.java | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/org/traccar/protocol/Arnavi4FrameDecoder.java index eaf829cc3..97bf75a20 100644 --- a/src/org/traccar/protocol/Arnavi4FrameDecoder.java +++ b/src/org/traccar/protocol/Arnavi4FrameDecoder.java @@ -10,7 +10,7 @@ import org.jboss.netty.handler.codec.frame.FrameDecoder; */ public class Arnavi4FrameDecoder extends FrameDecoder { - static final byte HEADER_START_SIGN = (byte)0xFF; + static final byte HEADER_START_SIGN = (byte) 0xFF; static final byte HEADER_VERSION_1 = 0x22; static final byte HEADER_VERSION_2 = 0x23; static final int HEADER_LENGTH = 10; diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index 46caebb71..c5ec3f31f 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -15,7 +15,11 @@ import java.util.Date; import java.util.LinkedList; import java.util.List; -import static org.traccar.protocol.Arnavi4FrameDecoder.*; +import static org.traccar.protocol.Arnavi4FrameDecoder.HEADER_START_SIGN; +import static org.traccar.protocol.Arnavi4FrameDecoder.HEADER_VERSION_1; +import static org.traccar.protocol.Arnavi4FrameDecoder.HEADER_VERSION_2; +import static org.traccar.protocol.Arnavi4FrameDecoder.PACKAGE_START_SIGN; +import static org.traccar.protocol.Arnavi4FrameDecoder.PACKAGE_END_SIGN; /** * Created by Ivan Muratov @binakot on 11.07.2017. @@ -99,9 +103,9 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { } else if (version == HEADER_VERSION_2) { response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 9); response.writeBytes(new byte[]{0x7B, 0x04, 0x00}); - byte[] timestampBytes = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)).array(); - response.writeByte(Checksum.modulo256(timestampBytes)); - response.writeBytes(timestampBytes); + byte[] timeBytes = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)).array(); + response.writeByte(Checksum.modulo256(timeBytes)); + response.writeBytes(timeBytes); response.writeByte(0x7D); } else { @@ -132,7 +136,7 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { case RECORD_DATA: case RECORD_TEXT: case RECORD_FILE: - case RECORD_BINARY: { + case RECORD_BINARY: int length = buf.readUnsignedShort(); long timestamp = buf.readUnsignedInt() * 1000; ChannelBuffer recordBuf = buf.readBytes(length); @@ -142,9 +146,7 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { } buf.readUnsignedByte(); // crc - break; - } default: throw new IllegalArgumentException("unsupported record type"); -- cgit v1.2.3 From 50d45d27beb423c1689f83401d0adb88b7fafb65 Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Fri, 14 Jul 2017 08:48:27 +0300 Subject: Correction based on comments. Re-write modulo256 checksum's parameter to byte array, not varargs. Split the tests to two methods for HEADER ver1 and ver2. Remove above-class copyrights, added top-file copyrights. Rename parcelNumber to index. Rename recordStartSign to recordType. Remove crearing additional buffer for record data, use origin buffer instead. Added check on minimal length of packet to avoid the out-of-range exceptions. --- src/org/traccar/helper/Checksum.java | 2 +- src/org/traccar/protocol/Arnavi4FrameDecoder.java | 22 +++++++-- src/org/traccar/protocol/Arnavi4Protocol.java | 18 ++++++-- .../traccar/protocol/Arnavi4ProtocolDecoder.java | 52 ++++++++++++++-------- test/org/traccar/helper/ChecksumTest.java | 7 ++- .../traccar/protocol/Arnavi4FrameDecoderTest.java | 3 -- .../protocol/Arnavi4ProtocolDecoderTest.java | 11 +++-- 7 files changed, 77 insertions(+), 38 deletions(-) diff --git a/src/org/traccar/helper/Checksum.java b/src/org/traccar/helper/Checksum.java index 7a0151d36..44cef9635 100644 --- a/src/org/traccar/helper/Checksum.java +++ b/src/org/traccar/helper/Checksum.java @@ -243,7 +243,7 @@ public final class Checksum { return (10 - (checksum % 10)) % 10; } - public static int modulo256(byte... bytes) { + public static int modulo256(byte[] bytes) { int sum = 0; for (byte b : bytes) { sum = (sum + b) & 0xFF; diff --git a/src/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/org/traccar/protocol/Arnavi4FrameDecoder.java index 97bf75a20..2587420c9 100644 --- a/src/org/traccar/protocol/Arnavi4FrameDecoder.java +++ b/src/org/traccar/protocol/Arnavi4FrameDecoder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2017 Ivan Muratov (binakot@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.traccar.protocol; import org.jboss.netty.buffer.ChannelBuffer; @@ -5,11 +20,10 @@ import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.FrameDecoder; -/** - * Created by Ivan Muratov @binakot on 12.07.2017. - */ public class Arnavi4FrameDecoder extends FrameDecoder { + static final int PACKET_MIN_LENGTH = 4; + static final byte HEADER_START_SIGN = (byte) 0xFF; static final byte HEADER_VERSION_1 = 0x22; static final byte HEADER_VERSION_2 = 0x23; @@ -26,7 +40,7 @@ public class Arnavi4FrameDecoder extends FrameDecoder { Channel channel, ChannelBuffer buf) throws Exception { - if (buf.readableBytes() == 0) { + if (buf.readableBytes() < PACKET_MIN_LENGTH) { return null; } diff --git a/src/org/traccar/protocol/Arnavi4Protocol.java b/src/org/traccar/protocol/Arnavi4Protocol.java index 227397980..381a9b457 100644 --- a/src/org/traccar/protocol/Arnavi4Protocol.java +++ b/src/org/traccar/protocol/Arnavi4Protocol.java @@ -1,3 +1,18 @@ +/* + * Copyright 2017 Ivan Muratov (binakot@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.traccar.protocol; import org.jboss.netty.bootstrap.ServerBootstrap; @@ -8,9 +23,6 @@ import org.traccar.TrackerServer; import java.nio.ByteOrder; import java.util.List; -/** - * Created by Ivan Muratov @binakot on 11.07.2017. - */ public class Arnavi4Protocol extends BaseProtocol { public Arnavi4Protocol() { diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index c5ec3f31f..232e8f053 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2017 Ivan Muratov (binakot@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.traccar.protocol; import org.jboss.netty.buffer.ChannelBuffer; @@ -21,9 +36,6 @@ import static org.traccar.protocol.Arnavi4FrameDecoder.HEADER_VERSION_2; import static org.traccar.protocol.Arnavi4FrameDecoder.PACKAGE_START_SIGN; import static org.traccar.protocol.Arnavi4FrameDecoder.PACKAGE_END_SIGN; -/** - * Created by Ivan Muratov @binakot on 11.07.2017. - */ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { private static final byte RECORD_PING = 0x00; @@ -40,18 +52,19 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { super(protocol); } - private Position decodePosition(DeviceSession deviceSession, ChannelBuffer buf, long timestamp) { + private Position decodePosition(DeviceSession deviceSession, ChannelBuffer buf, int length, Date time) { final Position position = new Position(); position.setProtocol(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - position.setTime(new Date(timestamp)); + position.setTime(time); - while (buf.readableBytes() > 0) { - short tagId = buf.readUnsignedByte(); + int readBytes = 0; + while (readBytes < length) { + short tag = buf.readUnsignedByte(); int tagValue = buf.readInt(); - switch (tagId) { + switch (tag) { case TAG_LATITUDE: position.setLatitude(Float.intBitsToFloat(tagValue)); position.setValid(true); @@ -72,6 +85,8 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { default: break; // Skip other tags } + + readBytes += 5; // 1 byte tag + 4 bytes value } return position; @@ -127,37 +142,36 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { List positions = new LinkedList<>(); - int parcelNumber = buf.readUnsignedByte(); + int index = buf.readUnsignedByte(); - byte recordStartSign = buf.readByte(); - while (recordStartSign != PACKAGE_END_SIGN) { - switch (recordStartSign) { + byte recordType = buf.readByte(); + while (recordType != PACKAGE_END_SIGN) { + switch (recordType) { case RECORD_PING: case RECORD_DATA: case RECORD_TEXT: case RECORD_FILE: case RECORD_BINARY: int length = buf.readUnsignedShort(); - long timestamp = buf.readUnsignedInt() * 1000; - ChannelBuffer recordBuf = buf.readBytes(length); + Date time = new Date(buf.readUnsignedInt() * 1000); - if (recordStartSign == RECORD_DATA) { - positions.add(decodePosition(deviceSession, recordBuf, timestamp)); + if (recordType == RECORD_DATA) { + positions.add(decodePosition(deviceSession, buf, length, time)); } buf.readUnsignedByte(); // crc break; default: - throw new IllegalArgumentException("unsupported record type"); + return null; // Unsupported types of package } - recordStartSign = buf.readByte(); + recordType = buf.readByte(); } if (channel != null) { final ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 4); - response.writeBytes(new byte[]{0x7B, 0x00, (byte) parcelNumber, 0x7D}); + response.writeBytes(new byte[]{0x7B, 0x00, (byte) index, 0x7D}); channel.write(response); } diff --git a/test/org/traccar/helper/ChecksumTest.java b/test/org/traccar/helper/ChecksumTest.java index 737b65c62..c7c5031df 100644 --- a/test/org/traccar/helper/ChecksumTest.java +++ b/test/org/traccar/helper/ChecksumTest.java @@ -4,7 +4,6 @@ import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.junit.Assert; import org.junit.Test; -import org.traccar.protocol.Arnavi4ProtocolDecoder; import java.nio.charset.StandardCharsets; @@ -31,9 +30,9 @@ public class ChecksumTest { @Test public void testModulo256() { - Assert.assertEquals(0x00, Checksum.modulo256((byte)0x00)); - Assert.assertEquals(0x00, Checksum.modulo256((byte)0x00, (byte)0x00, (byte)0x00)); - Assert.assertEquals(0x06, Checksum.modulo256((byte)0x01, (byte)0x02, (byte)0x03)); + Assert.assertEquals(0x00, Checksum.modulo256(new byte[] {0x00})); + Assert.assertEquals(0x00, Checksum.modulo256(new byte[] {0x00, 0x00, 0x00})); + Assert.assertEquals(0x06, Checksum.modulo256(new byte[] {0x01, 0x02, 0x03})); } } diff --git a/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java b/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java index 08abd3835..0b502bc36 100644 --- a/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java +++ b/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java @@ -6,9 +6,6 @@ import org.traccar.ProtocolTest; import java.nio.ByteOrder; -/** - * Created by Ivan Muratov @binakot on 13.07.2017. - */ public class Arnavi4FrameDecoderTest extends ProtocolTest { @Test diff --git a/test/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java b/test/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java index 2395572a1..d789b1c9c 100644 --- a/test/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java @@ -5,13 +5,10 @@ import org.traccar.ProtocolTest; import java.nio.ByteOrder; -/** - * Created by Ivan Muratov @binakot on 11.07.2017. - */ public class Arnavi4ProtocolDecoderTest extends ProtocolTest { @Test - public void testDecode() throws Exception { + public void testHeader1Decode() throws Exception { Arnavi4ProtocolDecoder decoder; @@ -23,6 +20,12 @@ public class Arnavi4ProtocolDecoderTest extends ProtocolTest { verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid PACKAGE packet with one DATA packet "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); + } + + @Test + public void testHeader2Decode() throws Exception { + + Arnavi4ProtocolDecoder decoder; decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); -- cgit v1.2.3 From a71dd10a966b491c64232180a2075450f0a258db Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Fri, 14 Jul 2017 09:32:52 +0300 Subject: Switch from the unnecessary creating the byte array to direct working with origin buffer. Remove tag value parsing inside case block. --- src/org/traccar/protocol/Arnavi4FrameDecoder.java | 15 ++++++--------- src/org/traccar/protocol/Arnavi4ProtocolDecoder.java | 17 +++++++++-------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/org/traccar/protocol/Arnavi4FrameDecoder.java index 2587420c9..a50ece641 100644 --- a/src/org/traccar/protocol/Arnavi4FrameDecoder.java +++ b/src/org/traccar/protocol/Arnavi4FrameDecoder.java @@ -44,19 +44,16 @@ public class Arnavi4FrameDecoder extends FrameDecoder { return null; } - byte[] bytes = new byte[buf.readableBytes()]; - buf.getBytes(0, bytes); - - if (bytes[0] == HEADER_START_SIGN - && bytes.length == HEADER_LENGTH - && (bytes[1] == HEADER_VERSION_1 || bytes[1] == HEADER_VERSION_2)) { + if (buf.getByte(0) == HEADER_START_SIGN + && buf.readableBytes() == HEADER_LENGTH + && (buf.getByte(1) == HEADER_VERSION_1 || buf.getByte(1) == HEADER_VERSION_2)) { return buf.readBytes(HEADER_LENGTH); } - int parcelNumber = bytes[1] & 0xFF; - if (bytes[0] == PACKAGE_START_SIGN && bytes[bytes.length - 1] == PACKAGE_END_SIGN + int parcelNumber = buf.getByte(1) & 0xFF; + if (buf.getByte(0) == PACKAGE_START_SIGN && buf.getByte(buf.readableBytes() - 1) == PACKAGE_END_SIGN && parcelNumber >= PACKAGE_MIN_PARCEL_NUMBER && parcelNumber <= PACKAGE_MAX_PARCEL_NUMBER) { - return buf.readBytes(bytes.length); + return buf; } return null; diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index 232e8f053..e2a1da29f 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -63,27 +63,28 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { int readBytes = 0; while (readBytes < length) { short tag = buf.readUnsignedByte(); - int tagValue = buf.readInt(); switch (tag) { case TAG_LATITUDE: - position.setLatitude(Float.intBitsToFloat(tagValue)); + position.setLatitude(buf.readFloat()); position.setValid(true); break; case TAG_LONGITUDE: - position.setLongitude(Float.intBitsToFloat(tagValue)); + position.setLongitude(buf.readFloat()); position.setValid(true); break; case TAG_COORD_PARAMS: - position.setSpeed((tagValue >> 24) * 1.852); - position.set(Position.KEY_SATELLITES, (tagValue >> 16 & 0x0F) + (tagValue >> 20 & 0x0F)); - position.setAltitude((tagValue >> 8 & 0xFF) * 10.0); - position.setCourse((tagValue & 0xFF) * 2.0); + position.setCourse(buf.readUnsignedByte() * 2.0); + position.setAltitude(buf.readUnsignedByte() * 10.0); + byte satellites = buf.readByte(); + position.set(Position.KEY_SATELLITES, satellites & 0x0F + (satellites >> 4) & 0x0F); // gps + glonass + position.setSpeed(buf.readByte() * 1.852); break; default: - break; // Skip other tags + buf.readBytes(4); // Skip other tags + break; } readBytes += 5; // 1 byte tag + 4 bytes value -- cgit v1.2.3 From 9f2f7d21fefda741cf9e3d4d43b3195902ed0a2b Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Fri, 14 Jul 2017 09:39:58 +0300 Subject: Fix build issues. [ERROR] src/org/traccar/protocol/Arnavi4ProtocolDecoder.java:[81] (sizes) LineLength: Line is longer than 120 characters (found 121). --- src/org/traccar/protocol/Arnavi4ProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index e2a1da29f..539f6d35c 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -78,7 +78,7 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { position.setCourse(buf.readUnsignedByte() * 2.0); position.setAltitude(buf.readUnsignedByte() * 10.0); byte satellites = buf.readByte(); - position.set(Position.KEY_SATELLITES, satellites & 0x0F + (satellites >> 4) & 0x0F); // gps + glonass + position.set(Position.KEY_SATELLITES, satellites & 0x0F + (satellites >> 4) & 0x0F); // gps+glonass position.setSpeed(buf.readByte() * 1.852); break; -- cgit v1.2.3 From 8684f83d352e01effbe08cacaccb264d4d368575 Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Fri, 14 Jul 2017 09:48:16 +0300 Subject: Change signed byte to unsidned for tag value of movement speed. --- src/org/traccar/protocol/Arnavi4ProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index 539f6d35c..4422ff4a6 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -79,7 +79,7 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { position.setAltitude(buf.readUnsignedByte() * 10.0); byte satellites = buf.readByte(); position.set(Position.KEY_SATELLITES, satellites & 0x0F + (satellites >> 4) & 0x0F); // gps+glonass - position.setSpeed(buf.readByte() * 1.852); + position.setSpeed(buf.readUnsignedByte() * 1.852); break; default: -- cgit v1.2.3 From fd1d75cb1a6dd1a4af065fec66ab69fcaf359916 Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Fri, 14 Jul 2017 10:00:05 +0300 Subject: Add reading bytes from buffer for non-data packages. --- src/org/traccar/protocol/Arnavi4ProtocolDecoder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index 4422ff4a6..682fc1577 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -158,6 +158,8 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { if (recordType == RECORD_DATA) { positions.add(decodePosition(deviceSession, buf, length, time)); + } else { + buf.readBytes(length); // Skip other records } buf.readUnsignedByte(); // crc -- cgit v1.2.3 From 36eeb5c4fa86f6516585819bb76ca7b73fa4d28a Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Fri, 14 Jul 2017 12:28:41 +0300 Subject: Split responses to separate methods. Optimize math operations with course and altitude. Remove unnecessary check for package first byte. Remove exception throwing. Store speed in knots, but not in km/h. --- .../traccar/protocol/Arnavi4ProtocolDecoder.java | 118 ++++++++++----------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index 682fc1577..07e4d855c 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -52,6 +52,34 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { super(protocol); } + private void sendHeaderResponse(Channel channel, byte version) { + if (channel != null) { + final ChannelBuffer response; + if (version == HEADER_VERSION_1) { + response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 4); + response.writeBytes(new byte[]{0x7B, 0x00, 0x00, 0x7D}); + } else if (version == HEADER_VERSION_2) { + response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 9); + response.writeBytes(new byte[]{0x7B, 0x04, 0x00}); + byte[] timeBytes = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)).array(); + response.writeByte(Checksum.modulo256(timeBytes)); + response.writeBytes(timeBytes); + response.writeByte(0x7D); + } else { + return; // Ignore unsupported versions of header + } + channel.write(response); + } + } + + private void sendPackageResponse(Channel channel, int index) { + if (channel != null) { + final ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 4); + response.writeBytes(new byte[]{0x7B, 0x00, (byte) index, 0x7D}); + channel.write(response); + } + } + private Position decodePosition(DeviceSession deviceSession, ChannelBuffer buf, int length, Date time) { final Position position = new Position(); @@ -75,15 +103,15 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { break; case TAG_COORD_PARAMS: - position.setCourse(buf.readUnsignedByte() * 2.0); - position.setAltitude(buf.readUnsignedByte() * 10.0); + position.setCourse(buf.readUnsignedByte() * 2); + position.setAltitude(buf.readUnsignedByte() * 10); byte satellites = buf.readByte(); position.set(Position.KEY_SATELLITES, satellites & 0x0F + (satellites >> 4) & 0x0F); // gps+glonass - position.setSpeed(buf.readUnsignedByte() * 1.852); + position.setSpeed(buf.readUnsignedByte()); break; default: - buf.readBytes(4); // Skip other tags + buf.readBytes(4); // Skip unsupported tags break; } @@ -108,27 +136,8 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { String imei = String.valueOf(buf.readLong()); DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession != null && channel != null) { - - final ChannelBuffer response; - - if (version == HEADER_VERSION_1) { - response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 4); - response.writeBytes(new byte[]{0x7B, 0x00, 0x00, 0x7D}); - - } else if (version == HEADER_VERSION_2) { - response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 9); - response.writeBytes(new byte[]{0x7B, 0x04, 0x00}); - byte[] timeBytes = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)).array(); - response.writeByte(Checksum.modulo256(timeBytes)); - response.writeBytes(timeBytes); - response.writeByte(0x7D); - - } else { - throw new IllegalArgumentException("unsupported header version"); - } - - channel.write(response); + if (deviceSession != null) { + sendHeaderResponse(channel, version); } return null; @@ -139,49 +148,40 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { return null; } - if (startSign == PACKAGE_START_SIGN) { - - List positions = new LinkedList<>(); - - int index = buf.readUnsignedByte(); - - byte recordType = buf.readByte(); - while (recordType != PACKAGE_END_SIGN) { - switch (recordType) { - case RECORD_PING: - case RECORD_DATA: - case RECORD_TEXT: - case RECORD_FILE: - case RECORD_BINARY: - int length = buf.readUnsignedShort(); - Date time = new Date(buf.readUnsignedInt() * 1000); + List positions = new LinkedList<>(); - if (recordType == RECORD_DATA) { - positions.add(decodePosition(deviceSession, buf, length, time)); - } else { - buf.readBytes(length); // Skip other records - } + int index = buf.readUnsignedByte(); - buf.readUnsignedByte(); // crc - break; + byte recordType = buf.readByte(); + while (recordType != PACKAGE_END_SIGN && buf.readableBytes() != 1) { // The last end sign byte + switch (recordType) { + case RECORD_PING: + case RECORD_DATA: + case RECORD_TEXT: + case RECORD_FILE: + case RECORD_BINARY: + int length = buf.readUnsignedShort(); + Date time = new Date(buf.readUnsignedInt() * 1000); - default: - return null; // Unsupported types of package - } + if (recordType == RECORD_DATA) { + positions.add(decodePosition(deviceSession, buf, length, time)); + } else { + buf.readBytes(length); // Skip other records + } - recordType = buf.readByte(); - } + buf.readUnsignedByte(); // crc + break; - if (channel != null) { - final ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 4); - response.writeBytes(new byte[]{0x7B, 0x00, (byte) index, 0x7D}); - channel.write(response); + default: + return null; // Ignore unsupported types of package } - return positions; + recordType = buf.readByte(); } - return null; + sendPackageResponse(channel, index); + + return positions; } } -- cgit v1.2.3 From c8f648e0261ad46e9301db35f161140aabad880a Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Fri, 14 Jul 2017 13:29:52 +0300 Subject: Upgrade the frame decoder and remove unnecessary check for the last end sign byte in protocol decoder. Protocol decoder read the buffer until its over, because frame decoder garantee the correct package length. Added additional tests for frame decoding. --- src/org/traccar/protocol/Arnavi4FrameDecoder.java | 16 ++++++++++++---- src/org/traccar/protocol/Arnavi4ProtocolDecoder.java | 4 ++-- test/org/traccar/protocol/Arnavi4FrameDecoderTest.java | 16 ++++++++++++++-- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/org/traccar/protocol/Arnavi4FrameDecoder.java index a50ece641..bb130e6bb 100644 --- a/src/org/traccar/protocol/Arnavi4FrameDecoder.java +++ b/src/org/traccar/protocol/Arnavi4FrameDecoder.java @@ -50,10 +50,18 @@ public class Arnavi4FrameDecoder extends FrameDecoder { return buf.readBytes(HEADER_LENGTH); } - int parcelNumber = buf.getByte(1) & 0xFF; - if (buf.getByte(0) == PACKAGE_START_SIGN && buf.getByte(buf.readableBytes() - 1) == PACKAGE_END_SIGN - && parcelNumber >= PACKAGE_MIN_PARCEL_NUMBER && parcelNumber <= PACKAGE_MAX_PARCEL_NUMBER) { - return buf; + int index = buf.getByte(1) & 0xFF; // parcel number + if (buf.getByte(0) == PACKAGE_START_SIGN + && index >= PACKAGE_MIN_PARCEL_NUMBER && index <= PACKAGE_MAX_PARCEL_NUMBER) { + + // package: 1 byte start sign, 1 byte parcel number, packets, 1 byte end sign + int packetStartIndex = 2; + while (packetStartIndex + 8 < buf.readableBytes() && buf.getByte(packetStartIndex) != PACKAGE_END_SIGN) { + // packet: 1 byte type, 2 bytes length, 4 bytes unixtime, length-bytes data, 1 byte crc + packetStartIndex += buf.getUnsignedShort(packetStartIndex + 1) + 8; + } + + return buf.readBytes(packetStartIndex + 1); } return null; diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index 07e4d855c..ed11e1559 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -153,7 +153,7 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { int index = buf.readUnsignedByte(); byte recordType = buf.readByte(); - while (recordType != PACKAGE_END_SIGN && buf.readableBytes() != 1) { // The last end sign byte + while (buf.readableBytes() > 0) { switch (recordType) { case RECORD_PING: case RECORD_DATA: @@ -176,7 +176,7 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { return null; // Ignore unsupported types of package } - recordType = buf.readByte(); + recordType = buf.readByte(); // The last byte in package is end sign } sendPackageResponse(channel, index); diff --git a/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java b/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java index 0b502bc36..93d818f56 100644 --- a/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java +++ b/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java @@ -21,14 +21,26 @@ public class Arnavi4FrameDecoderTest extends ProtocolTest { binary(ByteOrder.LITTLE_ENDIAN, "ff23f30c45f5c90f0300"), decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "ff23f30c45f5c90f0300"))); - Assert.assertEquals( // Valid PACKAGE packet with one DATA packet + Assert.assertEquals( // Valid PACKAGE with answer to server on file transfer. + null, + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"))); + + Assert.assertEquals( // Valid PACKAGE with one DATA packet binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); - Assert.assertEquals( // Valid PACKAGE packet with two DATA packet + Assert.assertEquals( // Valid PACKAGE with two DATA packet binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); + Assert.assertEquals( // Valid PACKAGE with one TEXT packet. + null, + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "030700e3f16b50747261636361721b"))); + + Assert.assertEquals( // Valid PACKAGE with one BINARY packet. + null, + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "062000e3f16b5003298b5e4204cbd514420500191000080400ff021b"))); + } } \ No newline at end of file -- cgit v1.2.3 From 4d4b3e92d6bc29f2d178164200f4be14a2b0ce1a Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Fri, 14 Jul 2017 13:35:44 +0300 Subject: Fix build issues. [ERROR] src/org/traccar/protocol/Arnavi4ProtocolDecoder.java:[36,15] (imports) UnusedImports: Unused import - org.traccar.protocol.Arnavi4FrameDecoder.PACKAGE_START_SIGN. [ERROR] src/org/traccar/protocol/Arnavi4ProtocolDecoder.java:[37,15] (imports) UnusedImports: Unused import - org.traccar.protocol.Arnavi4FrameDecoder.PACKAGE_END_SIGN. --- src/org/traccar/protocol/Arnavi4ProtocolDecoder.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index ed11e1559..a1a9d2ea1 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -33,8 +33,6 @@ import java.util.List; import static org.traccar.protocol.Arnavi4FrameDecoder.HEADER_START_SIGN; import static org.traccar.protocol.Arnavi4FrameDecoder.HEADER_VERSION_1; import static org.traccar.protocol.Arnavi4FrameDecoder.HEADER_VERSION_2; -import static org.traccar.protocol.Arnavi4FrameDecoder.PACKAGE_START_SIGN; -import static org.traccar.protocol.Arnavi4FrameDecoder.PACKAGE_END_SIGN; public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { -- cgit v1.2.3 From 79147b8a6fc8a3bfe863c2e8d3c47db06af90bc8 Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Mon, 17 Jul 2017 10:58:49 +0300 Subject: Rewrite the code of frame decoder. Added tests with invalid packets. --- src/org/traccar/protocol/Arnavi4FrameDecoder.java | 39 +++++++++++++--------- .../traccar/protocol/Arnavi4FrameDecoderTest.java | 23 +++++++++++-- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/org/traccar/protocol/Arnavi4FrameDecoder.java index bb130e6bb..ee4aee32a 100644 --- a/src/org/traccar/protocol/Arnavi4FrameDecoder.java +++ b/src/org/traccar/protocol/Arnavi4FrameDecoder.java @@ -22,17 +22,18 @@ import org.jboss.netty.handler.codec.frame.FrameDecoder; public class Arnavi4FrameDecoder extends FrameDecoder { - static final int PACKET_MIN_LENGTH = 4; + private static final int PACKET_MINIMUM_LENGTH = 4; + private static final int RECORD_MINIMUM_LENGTH = 8; - static final byte HEADER_START_SIGN = (byte) 0xFF; + static final byte HEADER_START_SIGN = (byte) 0xff; static final byte HEADER_VERSION_1 = 0x22; static final byte HEADER_VERSION_2 = 0x23; - static final int HEADER_LENGTH = 10; + private static final int HEADER_LENGTH = 10; - static final byte PACKAGE_START_SIGN = 0x5B; - static final byte PACKAGE_END_SIGN = 0x5D; - static final int PACKAGE_MIN_PARCEL_NUMBER = 0x01; - static final int PACKAGE_MAX_PARCEL_NUMBER = 0xFB; + private static final byte PACKAGE_START_SIGN = 0x5b; + private static final byte PACKAGE_END_SIGN = 0x5d; + private static final int PACKAGE_MIN_PARCEL_NUMBER = 0x01; + private static final int PACKAGE_MAX_PARCEL_NUMBER = 0xfb; @Override protected Object decode( @@ -40,31 +41,37 @@ public class Arnavi4FrameDecoder extends FrameDecoder { Channel channel, ChannelBuffer buf) throws Exception { - if (buf.readableBytes() < PACKET_MIN_LENGTH) { + if (buf.readableBytes() < PACKET_MINIMUM_LENGTH) { return null; } if (buf.getByte(0) == HEADER_START_SIGN && buf.readableBytes() == HEADER_LENGTH && (buf.getByte(1) == HEADER_VERSION_1 || buf.getByte(1) == HEADER_VERSION_2)) { + return buf.readBytes(HEADER_LENGTH); } - int index = buf.getByte(1) & 0xFF; // parcel number + int index = buf.getUnsignedByte(1); // parcel number if (buf.getByte(0) == PACKAGE_START_SIGN && index >= PACKAGE_MIN_PARCEL_NUMBER && index <= PACKAGE_MAX_PARCEL_NUMBER) { - // package: 1 byte start sign, 1 byte parcel number, packets, 1 byte end sign - int packetStartIndex = 2; - while (packetStartIndex + 8 < buf.readableBytes() && buf.getByte(packetStartIndex) != PACKAGE_END_SIGN) { - // packet: 1 byte type, 2 bytes length, 4 bytes unixtime, length-bytes data, 1 byte crc - packetStartIndex += buf.getUnsignedShort(packetStartIndex + 1) + 8; + int bufferPosition = 2; // start sign + parcel number + while (bufferPosition + RECORD_MINIMUM_LENGTH < buf.readableBytes() + && buf.getByte(bufferPosition) != PACKAGE_END_SIGN) { + + int dataLength = buf.getUnsignedShort(bufferPosition + 1); + bufferPosition += RECORD_MINIMUM_LENGTH + dataLength; // type + data length + unixtime + data + crc } - return buf.readBytes(packetStartIndex + 1); + if (bufferPosition < buf.readableBytes() + && buf.getByte(bufferPosition) == PACKAGE_END_SIGN) { + + return buf.readBytes(bufferPosition + 1); // end sign + } } return null; } -} +} \ No newline at end of file diff --git a/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java b/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java index 93d818f56..2203cdafc 100644 --- a/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java +++ b/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java @@ -9,7 +9,7 @@ import java.nio.ByteOrder; public class Arnavi4FrameDecoderTest extends ProtocolTest { @Test - public void testDecode() throws Exception { + public void testDecodeValidPackets() throws Exception { Arnavi4FrameDecoder decoder = new Arnavi4FrameDecoder(); @@ -21,7 +21,7 @@ public class Arnavi4FrameDecoderTest extends ProtocolTest { binary(ByteOrder.LITTLE_ENDIAN, "ff23f30c45f5c90f0300"), decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "ff23f30c45f5c90f0300"))); - Assert.assertEquals( // Valid PACKAGE with answer to server on file transfer. + Assert.assertEquals( // Valid PACKAGE with answer to server on file transfer null, decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"))); @@ -43,4 +43,23 @@ public class Arnavi4FrameDecoderTest extends ProtocolTest { } + @Test + public void testDecodeInvalidPackets() throws Exception { + + Arnavi4FrameDecoder decoder = new Arnavi4FrameDecoder(); + + Assert.assertEquals( // Invalid PACKAGE with one DATA packet (missing last byte with end sign) + null, + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029"))); + + Assert.assertEquals( // Invalid PACKAGE with two DATA packet (missing last 10 bytes) + null, + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d00"))); + + Assert.assertEquals( // Valid PACKAGE with useless extra bytes at the end + binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d010203040506070809"))); + + } + } \ No newline at end of file -- cgit v1.2.3 From 31e972e169acf4a517ff10f8a64f0e0cf0b8df0e Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Mon, 17 Jul 2017 14:00:46 +0300 Subject: Refactoring of the ARNAVI4 protocol decoder. --- .../traccar/protocol/Arnavi4ProtocolDecoder.java | 35 ++++++++++------------ 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index a1a9d2ea1..4ab929cf7 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -50,34 +50,31 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { super(protocol); } - private void sendHeaderResponse(Channel channel, byte version) { + private void sendResponse(Channel channel, byte version, int index) { if (channel != null) { final ChannelBuffer response; if (version == HEADER_VERSION_1) { response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 4); - response.writeBytes(new byte[]{0x7B, 0x00, 0x00, 0x7D}); + response.writeByte(0x7b); + response.writeByte(0x00); + response.writeByte((byte) index); + response.writeByte(0x7d); } else if (version == HEADER_VERSION_2) { response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 9); - response.writeBytes(new byte[]{0x7B, 0x04, 0x00}); + response.writeByte(0x7b); + response.writeByte(0x04); + response.writeByte(0x00); byte[] timeBytes = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)).array(); response.writeByte(Checksum.modulo256(timeBytes)); response.writeBytes(timeBytes); - response.writeByte(0x7D); + response.writeByte(0x7d); } else { - return; // Ignore unsupported versions of header + return; // Ignore unsupported header's versions } channel.write(response); } } - - private void sendPackageResponse(Channel channel, int index) { - if (channel != null) { - final ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 4); - response.writeBytes(new byte[]{0x7B, 0x00, (byte) index, 0x7D}); - channel.write(response); - } - } - + private Position decodePosition(DeviceSession deviceSession, ChannelBuffer buf, int length, Date time) { final Position position = new Position(); @@ -135,7 +132,7 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); if (deviceSession != null) { - sendHeaderResponse(channel, version); + sendResponse(channel, version, 0); } return null; @@ -164,20 +161,20 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { if (recordType == RECORD_DATA) { positions.add(decodePosition(deviceSession, buf, length, time)); } else { - buf.readBytes(length); // Skip other records + buf.readBytes(length); // Skip other types of record } buf.readUnsignedByte(); // crc break; default: - return null; // Ignore unsupported types of package + return null; // Ignore unsupported types of record } - recordType = buf.readByte(); // The last byte in package is end sign + recordType = buf.readByte(); } - sendPackageResponse(channel, index); + sendResponse(channel, HEADER_VERSION_1, index); return positions; } -- cgit v1.2.3 From 05bcc7359b52cad0036bcb32888b7e999a3efb25 Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Mon, 17 Jul 2017 14:14:46 +0300 Subject: Fix build issues. --- src/org/traccar/protocol/Arnavi4FrameDecoder.java | 2 +- src/org/traccar/protocol/Arnavi4ProtocolDecoder.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/org/traccar/protocol/Arnavi4FrameDecoder.java index ee4aee32a..7c60cb934 100644 --- a/src/org/traccar/protocol/Arnavi4FrameDecoder.java +++ b/src/org/traccar/protocol/Arnavi4FrameDecoder.java @@ -74,4 +74,4 @@ public class Arnavi4FrameDecoder extends FrameDecoder { return null; } -} \ No newline at end of file +} diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index 4ab929cf7..e3e027993 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -74,7 +74,7 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { channel.write(response); } } - + private Position decodePosition(DeviceSession deviceSession, ChannelBuffer buf, int length, Date time) { final Position position = new Position(); -- cgit v1.2.3 From d225018f7aadefab6381d5283347bae10e153bfa Mon Sep 17 00:00:00 2001 From: Ivan Muratov Date: Tue, 24 Oct 2017 14:45:30 +0300 Subject: Arnavi4 frame decoder's code reorganization based on traccar maintainer comments. --- setup/default.xml | 5 +- src/org/traccar/protocol/Arnavi4FrameDecoder.java | 69 +++++++++++----------- .../traccar/protocol/Arnavi4ProtocolDecoder.java | 8 +-- .../traccar/protocol/Arnavi4FrameDecoderTest.java | 43 +++++--------- 4 files changed, 55 insertions(+), 70 deletions(-) diff --git a/setup/default.xml b/setup/default.xml index 223b9a585..1e84c5218 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -579,6 +579,9 @@ 5143 5144 5145 - 5146 + 5146 + 5147 + 5148 + 5149 diff --git a/src/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/org/traccar/protocol/Arnavi4FrameDecoder.java index 7c60cb934..b13f3fd7d 100644 --- a/src/org/traccar/protocol/Arnavi4FrameDecoder.java +++ b/src/org/traccar/protocol/Arnavi4FrameDecoder.java @@ -22,53 +22,50 @@ import org.jboss.netty.handler.codec.frame.FrameDecoder; public class Arnavi4FrameDecoder extends FrameDecoder { - private static final int PACKET_MINIMUM_LENGTH = 4; - private static final int RECORD_MINIMUM_LENGTH = 8; - - static final byte HEADER_START_SIGN = (byte) 0xff; - static final byte HEADER_VERSION_1 = 0x22; - static final byte HEADER_VERSION_2 = 0x23; + private static final int MIN_LENGTH = 4; private static final int HEADER_LENGTH = 10; - - private static final byte PACKAGE_START_SIGN = 0x5b; + private static final int PACKET_WRAPPER_LENGTH = 8; + private static final int COMMAND_ANSWER_PACKET_LENGTH = 4; + private static final int COMMAND_ANSWER_PARCEL_NUMBER = 0xfd; private static final byte PACKAGE_END_SIGN = 0x5d; - private static final int PACKAGE_MIN_PARCEL_NUMBER = 0x01; - private static final int PACKAGE_MAX_PARCEL_NUMBER = 0xfb; + + private boolean firstPacket = true; @Override protected Object decode( - ChannelHandlerContext ctx, - Channel channel, - ChannelBuffer buf) throws Exception { + ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception { - if (buf.readableBytes() < PACKET_MINIMUM_LENGTH) { + if (buf.readableBytes() < MIN_LENGTH) { return null; } - if (buf.getByte(0) == HEADER_START_SIGN - && buf.readableBytes() == HEADER_LENGTH - && (buf.getByte(1) == HEADER_VERSION_1 || buf.getByte(1) == HEADER_VERSION_2)) { - - return buf.readBytes(HEADER_LENGTH); - } - - int index = buf.getUnsignedByte(1); // parcel number - if (buf.getByte(0) == PACKAGE_START_SIGN - && index >= PACKAGE_MIN_PARCEL_NUMBER && index <= PACKAGE_MAX_PARCEL_NUMBER) { - - int bufferPosition = 2; // start sign + parcel number - while (bufferPosition + RECORD_MINIMUM_LENGTH < buf.readableBytes() - && buf.getByte(bufferPosition) != PACKAGE_END_SIGN) { - - int dataLength = buf.getUnsignedShort(bufferPosition + 1); - bufferPosition += RECORD_MINIMUM_LENGTH + dataLength; // type + data length + unixtime + data + crc + int length; + if (firstPacket) { + firstPacket = false; + length = HEADER_LENGTH; + } else { + int index = buf.getUnsignedByte(1); // parcel number + if (index == COMMAND_ANSWER_PARCEL_NUMBER) { + length = COMMAND_ANSWER_PACKET_LENGTH; + } else { + int pos = 2; // start sign + parcel number + while (pos + PACKET_WRAPPER_LENGTH < buf.readableBytes() + && buf.getByte(pos) != PACKAGE_END_SIGN) { + + int dataLength = buf.getUnsignedShort(pos + 1); + pos += PACKET_WRAPPER_LENGTH + dataLength; // packet type + data length + unixtime + data + crc + } + + if (buf.getByte(pos) != PACKAGE_END_SIGN) { // end sign + return null; + } + + length = pos + 1; } + } - if (bufferPosition < buf.readableBytes() - && buf.getByte(bufferPosition) == PACKAGE_END_SIGN) { - - return buf.readBytes(bufferPosition + 1); // end sign - } + if (buf.readableBytes() >= length) { + return buf.readBytes(length); } return null; diff --git a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java index e3e027993..06abb563f 100644 --- a/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -30,12 +30,12 @@ import java.util.Date; import java.util.LinkedList; import java.util.List; -import static org.traccar.protocol.Arnavi4FrameDecoder.HEADER_START_SIGN; -import static org.traccar.protocol.Arnavi4FrameDecoder.HEADER_VERSION_1; -import static org.traccar.protocol.Arnavi4FrameDecoder.HEADER_VERSION_2; - public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { + private static final byte HEADER_START_SIGN = (byte) 0xff; + private static final byte HEADER_VERSION_1 = 0x22; + private static final byte HEADER_VERSION_2 = 0x23; + private static final byte RECORD_PING = 0x00; private static final byte RECORD_DATA = 0x01; private static final byte RECORD_TEXT = 0x03; diff --git a/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java b/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java index 2203cdafc..b634f0cdc 100644 --- a/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java +++ b/test/org/traccar/protocol/Arnavi4FrameDecoderTest.java @@ -17,14 +17,6 @@ public class Arnavi4FrameDecoderTest extends ProtocolTest { binary(ByteOrder.LITTLE_ENDIAN, "ff22f30c45f5c90f0300"), decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "ff22f30c45f5c90f0300"))); - Assert.assertEquals( // Valid HEADER v2 packet with IMEI - binary(ByteOrder.LITTLE_ENDIAN, "ff23f30c45f5c90f0300"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "ff23f30c45f5c90f0300"))); - - Assert.assertEquals( // Valid PACKAGE with answer to server on file transfer - null, - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"))); - Assert.assertEquals( // Valid PACKAGE with one DATA packet binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); @@ -34,31 +26,24 @@ public class Arnavi4FrameDecoderTest extends ProtocolTest { decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); Assert.assertEquals( // Valid PACKAGE with one TEXT packet. - null, - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "030700e3f16b50747261636361721b"))); + binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b5d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b5d"))); - Assert.assertEquals( // Valid PACKAGE with one BINARY packet. - null, - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "062000e3f16b5003298b5e4204cbd514420500191000080400ff021b"))); - - } + Assert.assertEquals( // Valid PACKAGE with two TEXT packet. + binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"))); - @Test - public void testDecodeInvalidPackets() throws Exception { - - Arnavi4FrameDecoder decoder = new Arnavi4FrameDecoder(); - - Assert.assertEquals( // Invalid PACKAGE with one DATA packet (missing last byte with end sign) - null, - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029"))); + Assert.assertEquals( // Valid PACKAGE with one BINARY packet. + binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); - Assert.assertEquals( // Invalid PACKAGE with two DATA packet (missing last 10 bytes) - null, - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d00"))); + Assert.assertEquals( // Valid PACKAGE with two BINARY packet. + binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); - Assert.assertEquals( // Valid PACKAGE with useless extra bytes at the end - binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d010203040506070809"))); + Assert.assertEquals( // Valid PACKAGE with answer to server on file transfer + binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"))); } -- cgit v1.2.3 From 72e8ab6966cb70dd58dcdf671dab11a7673aeabf Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Mon, 26 Aug 2019 06:08:50 -0400 Subject: Add a ring buffer and response check --- src/main/java/org/traccar/WebDataHandler.java | 89 +++++++++++++++++++++++---- src/main/java/org/traccar/config/Keys.java | 7 +++ 2 files changed, 85 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java index 64396de03..193efd230 100644 --- a/src/main/java/org/traccar/WebDataHandler.java +++ b/src/main/java/org/traccar/WebDataHandler.java @@ -27,9 +27,11 @@ import org.traccar.model.Position; import org.traccar.model.Group; import javax.inject.Inject; +import javax.ws.rs.core.Response; import javax.ws.rs.client.Client; import javax.ws.rs.client.Entity; import javax.ws.rs.client.Invocation; +import javax.ws.rs.client.InvocationCallback; import java.util.HashMap; import java.util.Map; import java.io.UnsupportedEncodingException; @@ -39,6 +41,14 @@ import java.util.Calendar; import java.util.Formatter; import java.util.Locale; import java.util.TimeZone; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.commons.collections.Buffer; +import org.apache.commons.collections.BufferUtils; +import org.apache.commons.collections.buffer.CircularFifoBuffer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @ChannelHandler.Sharable public class WebDataHandler extends BaseDataHandler { @@ -46,6 +56,8 @@ public class WebDataHandler extends BaseDataHandler { private static final String KEY_POSITION = "position"; private static final String KEY_DEVICE = "device"; + private static final Logger LOGGER = LoggerFactory.getLogger(WebDataHandler.class); + private final IdentityManager identityManager; private final ObjectMapper objectMapper; private final Client client; @@ -54,6 +66,13 @@ public class WebDataHandler extends BaseDataHandler { private final String header; private final boolean json; + private final Integer queueSize; + + private Buffer positionsQueue = null; + private AtomicBoolean sendInProgress; + + private Invocation.Builder requestBuilder; + @Inject public WebDataHandler( Config config, IdentityManager identityManager, ObjectMapper objectMapper, Client client) { @@ -63,6 +82,12 @@ public class WebDataHandler extends BaseDataHandler { this.url = config.getString(Keys.FORWARD_URL); this.header = config.getString(Keys.FORWARD_HEADER); this.json = config.getBoolean(Keys.FORWARD_JSON); + Integer queueSize = (config.getInteger(Keys.FORWARD_QUEUE_SIZE, 0)); + this.queueSize = (queueSize > 0) ? queueSize : 0; + if (this.queueSize > 0) { + this.positionsQueue = BufferUtils.synchronizedBuffer(new CircularFifoBuffer(this.queueSize)); + } + this.sendInProgress = new AtomicBoolean(false); } private static String formatSentence(Position position) { @@ -152,9 +177,7 @@ public class WebDataHandler extends BaseDataHandler { return request; } - @Override - protected Position handlePosition(Position position) { - + protected void sendPosition(Position position) { String url; if (json) { url = this.url; @@ -166,19 +189,63 @@ public class WebDataHandler extends BaseDataHandler { } } - Invocation.Builder requestBuilder = client.target(url).request(); - - if (header != null && !header.isEmpty()) { - for (String line: header.split("\\r?\\n")) { - String[] values = line.split(":", 2); - requestBuilder.header(values[0].trim(), values[1].trim()); + if (!json || requestBuilder == null) { + requestBuilder = client.target(url).request(); + if (header != null && !header.isEmpty()) { + for (String line: header.split("\\r?\\n")) { + String[] values = line.split(":", 2); + requestBuilder.header(values[0].trim(), values[1].trim()); + } } } + InvocationCallback callback = new InvocationCallback() { + public void completed(Response response) { + if (positionsQueue != null) { + if (response.getStatus() == 200) { + positionsQueue.remove(); + } + logQueueStatus(); + sendInProgress.set(false); + sendQueuedPositions(); + } + } + public void failed(Throwable throwable) { + if (positionsQueue != null) { + logQueueStatus(); + sendInProgress.set(false); + sendQueuedPositions(); + } + } + }; + if (json) { - requestBuilder.async().post(Entity.json(prepareJsonPayload(position))); + requestBuilder.async().post(Entity.json(prepareJsonPayload(position)), callback); + } else { + requestBuilder.async().get(callback); + } + } + + protected void logQueueStatus() { + LOGGER.info(String.format("Position forwarding queue: %d/%d", + positionsQueue.size(), queueSize)); + } + + protected void sendQueuedPositions() { + if (!positionsQueue.isEmpty() && !sendInProgress.get()) { + sendInProgress.set(true); + sendPosition((Position) positionsQueue.get()); + } + } + + @Override + protected Position handlePosition(Position position) { + + if (positionsQueue == null) { + sendPosition(position); } else { - requestBuilder.async().get(); + positionsQueue.add(position); + sendQueuedPositions(); } return position; diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 2c5dcefd5..10eda01e2 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -100,6 +100,13 @@ public final class Keys { public static final ConfigKey FORWARD_JSON = new ConfigKey( "forward.json", Boolean.class); + /** + * Position forwarding queue size. A ring buffer of the specified size is used to queue positions. + * If negative, zero, or not specified, queueing is disabled. (Legacy behaviour) + */ + public static final ConfigKey FORWARD_QUEUE_SIZE = new ConfigKey( + "forward.queue.size", Integer.class); + /** * Boolean flag to enable or disable position filtering. */ -- cgit v1.2.3 From 169c40cc7207a962f027aea85bd8f9c04b33738f Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Sat, 31 Aug 2019 18:27:13 -0400 Subject: Refactor code to have concurrency --- src/main/java/org/traccar/WebDataHandler.java | 141 ++++++++++++++++---------- src/main/java/org/traccar/config/Keys.java | 7 ++ 2 files changed, 93 insertions(+), 55 deletions(-) diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java index 193efd230..dfd6f0e5b 100644 --- a/src/main/java/org/traccar/WebDataHandler.java +++ b/src/main/java/org/traccar/WebDataHandler.java @@ -41,7 +41,7 @@ import java.util.Calendar; import java.util.Formatter; import java.util.Locale; import java.util.TimeZone; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.collections.Buffer; import org.apache.commons.collections.BufferUtils; @@ -67,27 +67,33 @@ public class WebDataHandler extends BaseDataHandler { private final boolean json; private final Integer queueSize; + private final Integer queueConcurrency; private Buffer positionsQueue = null; - private AtomicBoolean sendInProgress; - - private Invocation.Builder requestBuilder; + private AtomicInteger pendingRequests; @Inject public WebDataHandler( Config config, IdentityManager identityManager, ObjectMapper objectMapper, Client client) { + this.identityManager = identityManager; this.objectMapper = objectMapper; this.client = client; this.url = config.getString(Keys.FORWARD_URL); this.header = config.getString(Keys.FORWARD_HEADER); this.json = config.getBoolean(Keys.FORWARD_JSON); + Integer queueSize = (config.getInteger(Keys.FORWARD_QUEUE_SIZE, 0)); this.queueSize = (queueSize > 0) ? queueSize : 0; + + Integer queueConcurrency = (config.getInteger(Keys.FORWARD_QUEUE_CONCURRENCY, 1)); + this.queueConcurrency = (queueConcurrency > 0) ? queueConcurrency : 1; + if (this.queueSize > 0) { this.positionsQueue = BufferUtils.synchronizedBuffer(new CircularFifoBuffer(this.queueSize)); } - this.sendInProgress = new AtomicBoolean(false); + + this.pendingRequests = new AtomicInteger(0); } private static String formatSentence(Position position) { @@ -177,80 +183,105 @@ public class WebDataHandler extends BaseDataHandler { return request; } - protected void sendPosition(Position position) { - String url; - if (json) { - url = this.url; - } else { - try { - url = formatRequest(position); - } catch (UnsupportedEncodingException | JsonProcessingException e) { - throw new RuntimeException("Forwarding formatting error", e); + @Override + protected Position handlePosition(Position position) { + + class AsyncRequestAndCallback implements InvocationCallback { + + private Map jsonPayload; + private Invocation.Builder requestBuilder; + + AsyncRequestAndCallback(Position position) { + + String formattedUrl; + try { + formattedUrl = (json) ? url : formatRequest(position); + } catch (UnsupportedEncodingException | JsonProcessingException e) { + throw new RuntimeException("Forwarding formatting error", e); + } + + requestBuilder = client.target(formattedUrl).request(); + if (header != null && !header.isEmpty()) { + for (String line: header.split("\\r?\\n")) { + String[] values = line.split(":", 2); + requestBuilder.header(values[0].trim(), values[1].trim()); + } + } + + if (json) { + jsonPayload = prepareJsonPayload(position); + } + + pendingRequests.incrementAndGet(); + + send(); } - } - if (!json || requestBuilder == null) { - requestBuilder = client.target(url).request(); - if (header != null && !header.isEmpty()) { - for (String line: header.split("\\r?\\n")) { - String[] values = line.split(":", 2); - requestBuilder.header(values[0].trim(), values[1].trim()); + private void send() { + if (json) { + requestBuilder.async().post(Entity.json(jsonPayload), this); + } else { + requestBuilder.async().get(this); + } + } + + private void retry() { + try { + Thread.sleep(1000); + send(); + } catch (Exception e) { + } + } + + private void next() { + if (!positionsQueue.isEmpty()) { + new AsyncRequestAndCallback((Position) positionsQueue.remove()); } } - } - InvocationCallback callback = new InvocationCallback() { public void completed(Response response) { if (positionsQueue != null) { - if (response.getStatus() == 200) { - positionsQueue.remove(); + boolean ok = (response.getStatus() == 200); + boolean retry = (positionsQueue.size() < queueSize); + if (!ok && retry) { + retry(); + } else { + pendingRequests.decrementAndGet(); + while (!positionsQueue.isEmpty() && pendingRequests.get() < queueConcurrency) { + next(); + } } - logQueueStatus(); - sendInProgress.set(false); - sendQueuedPositions(); } } + public void failed(Throwable throwable) { if (positionsQueue != null) { - logQueueStatus(); - sendInProgress.set(false); - sendQueuedPositions(); + if (positionsQueue.size() < queueSize) { + retry(); + } else if (pendingRequests.decrementAndGet() == 0) { + next(); + } } } - }; - - if (json) { - requestBuilder.async().post(Entity.json(prepareJsonPayload(position)), callback); - } else { - requestBuilder.async().get(callback); - } - } - - protected void logQueueStatus() { - LOGGER.info(String.format("Position forwarding queue: %d/%d", - positionsQueue.size(), queueSize)); - } - protected void sendQueuedPositions() { - if (!positionsQueue.isEmpty() && !sendInProgress.get()) { - sendInProgress.set(true); - sendPosition((Position) positionsQueue.get()); } - } - @Override - protected Position handlePosition(Position position) { - - if (positionsQueue == null) { - sendPosition(position); + if (positionsQueue == null || pendingRequests.get() == 0) { + new AsyncRequestAndCallback(position); } else { positionsQueue.add(position); - sendQueuedPositions(); } + logQueueStatus(); + return position; } + private void logQueueStatus() { + LOGGER.info(String.format("Position forwarding queue: %d/%d/%d", + pendingRequests.get(), positionsQueue.size(), queueSize)); + } + private Map prepareJsonPayload(Position position) { Map data = new HashMap<>(); diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 10eda01e2..6102f7604 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -107,6 +107,13 @@ public final class Keys { public static final ConfigKey FORWARD_QUEUE_SIZE = new ConfigKey( "forward.queue.size", Integer.class); + /** + * Position forwarding queue concurrency. Defines how many HTTP requests can be pending at any time. + * If queueing is enabled, and this value is less than one, it's ignored and forced to be one. + */ + public static final ConfigKey FORWARD_QUEUE_CONCURRENCY = new ConfigKey( + "forward.queue.concurrency", Integer.class); + /** * Boolean flag to enable or disable position filtering. */ -- cgit v1.2.3 From 229c042edf74979d5893c047d2b5de7fd8cc8df0 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Sun, 1 Dec 2019 16:33:08 -0500 Subject: Implement wait and retry logic --- src/main/java/org/traccar/WebDataHandler.java | 102 +++++++++++--------------- src/main/java/org/traccar/config/Keys.java | 34 +++++++-- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java index dfd6f0e5b..19c5a58a8 100644 --- a/src/main/java/org/traccar/WebDataHandler.java +++ b/src/main/java/org/traccar/WebDataHandler.java @@ -43,21 +43,12 @@ import java.util.Locale; import java.util.TimeZone; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.commons.collections.Buffer; -import org.apache.commons.collections.BufferUtils; -import org.apache.commons.collections.buffer.CircularFifoBuffer; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - @ChannelHandler.Sharable public class WebDataHandler extends BaseDataHandler { private static final String KEY_POSITION = "position"; private static final String KEY_DEVICE = "device"; - private static final Logger LOGGER = LoggerFactory.getLogger(WebDataHandler.class); - private final IdentityManager identityManager; private final ObjectMapper objectMapper; private final Client client; @@ -66,11 +57,13 @@ public class WebDataHandler extends BaseDataHandler { private final String header; private final boolean json; - private final Integer queueSize; - private final Integer queueConcurrency; + private final Boolean retryEnabled; + private final Integer retryDelayMin; + private final Integer retryDelayMax; + private final Integer deliveryPendingLimit; - private Buffer positionsQueue = null; - private AtomicInteger pendingRequests; + private AtomicInteger deliveryFaliuresInRow; + private AtomicInteger deliveryPendingCurrent; @Inject public WebDataHandler( @@ -83,17 +76,19 @@ public class WebDataHandler extends BaseDataHandler { this.header = config.getString(Keys.FORWARD_HEADER); this.json = config.getBoolean(Keys.FORWARD_JSON); - Integer queueSize = (config.getInteger(Keys.FORWARD_QUEUE_SIZE, 0)); - this.queueSize = (queueSize > 0) ? queueSize : 0; + this.retryEnabled = config.getBoolean(Keys.FORWARD_RETRY_ENABLE); - Integer queueConcurrency = (config.getInteger(Keys.FORWARD_QUEUE_CONCURRENCY, 1)); - this.queueConcurrency = (queueConcurrency > 0) ? queueConcurrency : 1; + Integer retryDelayMin = config.getInteger(Keys.FORWARD_RETRY_DELAY_MIN, 1); + this.retryDelayMin = (retryDelayMin > 0 && retryDelayMin < 3600) ? retryDelayMin : 1; - if (this.queueSize > 0) { - this.positionsQueue = BufferUtils.synchronizedBuffer(new CircularFifoBuffer(this.queueSize)); - } + Integer retryDelayMax = config.getInteger(Keys.FORWARD_RETRY_DELAY_MAX, 10); + this.retryDelayMax = (retryDelayMax > retryDelayMin && retryDelayMax < 3600) ? retryDelayMax : retryDelayMin; + + Integer deliveryPendingLimit = config.getInteger(Keys.FORWARD_RETRY_PENDING_LIMIT, 100); + this.deliveryPendingLimit = (retryDelayMax > 0) ? deliveryPendingLimit : 100; - this.pendingRequests = new AtomicInteger(0); + this.deliveryFaliuresInRow = new AtomicInteger(0); + this.deliveryPendingCurrent = new AtomicInteger(0); } private static String formatSentence(Position position) { @@ -188,6 +183,7 @@ public class WebDataHandler extends BaseDataHandler { class AsyncRequestAndCallback implements InvocationCallback { + private Integer delay = retryDelayMin; private Map jsonPayload; private Invocation.Builder requestBuilder; @@ -212,7 +208,7 @@ public class WebDataHandler extends BaseDataHandler { jsonPayload = prepareJsonPayload(position); } - pendingRequests.incrementAndGet(); + deliveryPendingCurrent.incrementAndGet(); send(); } @@ -227,61 +223,47 @@ public class WebDataHandler extends BaseDataHandler { private void retry() { try { - Thread.sleep(1000); - send(); + deliveryFaliuresInRow.incrementAndGet(); + if (!retryEnabled || deliveryPendingCurrent.get() > deliveryPendingLimit) { + deliveryPendingCurrent.decrementAndGet(); + } else { + Integer i = 0; + for ( ; i < delay; i++) { + Thread.sleep(1000); + if (deliveryFaliuresInRow.get() == 0) { + delay = retryDelayMin; + break; + } + } + if (i >= delay && delay < retryDelayMax) { + delay++; + } + send(); + } } catch (Exception e) { } } - private void next() { - if (!positionsQueue.isEmpty()) { - new AsyncRequestAndCallback((Position) positionsQueue.remove()); - } - } - public void completed(Response response) { - if (positionsQueue != null) { - boolean ok = (response.getStatus() == 200); - boolean retry = (positionsQueue.size() < queueSize); - if (!ok && retry) { - retry(); - } else { - pendingRequests.decrementAndGet(); - while (!positionsQueue.isEmpty() && pendingRequests.get() < queueConcurrency) { - next(); - } - } + if (response.getStatus() == 200) { + deliveryFaliuresInRow.set(0); + deliveryPendingCurrent.decrementAndGet(); + } else { + retry(); } } public void failed(Throwable throwable) { - if (positionsQueue != null) { - if (positionsQueue.size() < queueSize) { - retry(); - } else if (pendingRequests.decrementAndGet() == 0) { - next(); - } - } + retry(); } } - if (positionsQueue == null || pendingRequests.get() == 0) { - new AsyncRequestAndCallback(position); - } else { - positionsQueue.add(position); - } - - logQueueStatus(); + new AsyncRequestAndCallback(position); return position; } - private void logQueueStatus() { - LOGGER.info(String.format("Position forwarding queue: %d/%d/%d", - pendingRequests.get(), positionsQueue.size(), queueSize)); - } - private Map prepareJsonPayload(Position position) { Map data = new HashMap<>(); diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 6102f7604..029316142 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -101,18 +101,36 @@ public final class Keys { "forward.json", Boolean.class); /** - * Position forwarding queue size. A ring buffer of the specified size is used to queue positions. - * If negative, zero, or not specified, queueing is disabled. (Legacy behaviour) + * Position forwarding retrying enable. When enabled, additional attempts are made to deliver positions. + * If initial delivery fails, because of an unreachable server or an HTTP response different from '200 OK', + * the software waits for 'forward.retry.delay.min' seconds to retry delivery. On subsecuent failures, this + * delay is incremented by 1 second up to 'forward.retry.delay.max'. On successful delivery, the delay is reset + * to 'forward.retry.delay.min'. Pending positions to be delivered are limited to 'forward.retry.pending.limit'. + * If this limit is reached, positions are discarded before next retry. */ - public static final ConfigKey FORWARD_QUEUE_SIZE = new ConfigKey( - "forward.queue.size", Integer.class); + public static final ConfigKey FORWARD_RETRY_ENABLE = new ConfigKey( + "forward.retry.enable", Boolean.class); /** - * Position forwarding queue concurrency. Defines how many HTTP requests can be pending at any time. - * If queueing is enabled, and this value is less than one, it's ignored and forced to be one. + * Position forwarding retry minimum delay in seconds. + * Can be set to anything between 1 and 3600 seconds. Defaults to 1 second. */ - public static final ConfigKey FORWARD_QUEUE_CONCURRENCY = new ConfigKey( - "forward.queue.concurrency", Integer.class); + public static final ConfigKey FORWARD_RETRY_DELAY_MIN = new ConfigKey( + "forward.retry.delay.min", Integer.class); + + /** + * Position forwarding retry maximum delay in seconds. + * Can be set to anything between 1 and 3600 seconds. Defaults to 10 seconds. + */ + public static final ConfigKey FORWARD_RETRY_DELAY_MAX = new ConfigKey( + "forward.retry.delay.max", Integer.class); + + /** + * Position forwarding retry pending limit. + * Can be set to anything greater than 0. Defaults to 100 positions. + */ + public static final ConfigKey FORWARD_RETRY_PENDING_LIMIT = new ConfigKey( + "forward.retry.pending.limit", Integer.class); /** * Boolean flag to enable or disable position filtering. -- cgit v1.2.3 From 628a80f49f286dcb51034c0e5fbc2f59fe295a08 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Sun, 1 Dec 2019 16:39:21 -0500 Subject: Fix orthographic typo. --- src/main/java/org/traccar/config/Keys.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 029316142..ec4eb1801 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -103,7 +103,7 @@ public final class Keys { /** * Position forwarding retrying enable. When enabled, additional attempts are made to deliver positions. * If initial delivery fails, because of an unreachable server or an HTTP response different from '200 OK', - * the software waits for 'forward.retry.delay.min' seconds to retry delivery. On subsecuent failures, this + * the software waits for 'forward.retry.delay.min' seconds to retry delivery. On subsequent failures, this * delay is incremented by 1 second up to 'forward.retry.delay.max'. On successful delivery, the delay is reset * to 'forward.retry.delay.min'. Pending positions to be delivered are limited to 'forward.retry.pending.limit'. * If this limit is reached, positions are discarded before next retry. -- cgit v1.2.3 From 0c40b37a389ae681152f320e47731ee3012f17eb Mon Sep 17 00:00:00 2001 From: jcardus Date: Tue, 21 Jan 2020 18:24:03 +0000 Subject: Here geocoder url config parameter (#4472) * here geocoder url config parameter * here geocoder url config parameter * added new parameter apiKey and kept app_code for retro compatibility added default url for here * fixed ident removed url from here geocode test * fixed ident intellij uses 2 spaces, this project uses 4. * fixed ident intellij uses 2 spaces, this project uses 4. * url should be null not "" * wrong file --- src/main/java/org/traccar/MainModule.java | 2 +- src/main/java/org/traccar/geocoder/HereGeocoder.java | 12 ++++++++---- src/test/java/org/traccar/geocoder/GeocoderTest.java | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 9adea61b0..0957d9fe3 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -170,7 +170,7 @@ public class MainModule extends AbstractModule { case "ban": return new BanGeocoder(cacheSize, addressFormat); case "here": - return new HereGeocoder(id, key, language, cacheSize, addressFormat); + return new HereGeocoder(url, id, key, language, cacheSize, addressFormat); case "mapmyindia": return new MapmyIndiaGeocoder(url, key, cacheSize, addressFormat); default: diff --git a/src/main/java/org/traccar/geocoder/HereGeocoder.java b/src/main/java/org/traccar/geocoder/HereGeocoder.java index 756260b52..aaf11d74d 100644 --- a/src/main/java/org/traccar/geocoder/HereGeocoder.java +++ b/src/main/java/org/traccar/geocoder/HereGeocoder.java @@ -19,20 +19,24 @@ import javax.json.JsonObject; public class HereGeocoder extends JsonGeocoder { - private static String formatUrl(String id, String key, String language) { - String url = "https://reverse.geocoder.api.here.com/6.2/reversegeocode.json"; + private static String formatUrl(String url, String id, String key, String language) { + if (url == null) { + url = "https://reverse.geocoder.ls.hereapi.com/6.2/reversegeocode.json"; + } url += "?mode=retrieveAddresses&maxresults=1"; url += "&prox=%f,%f,0"; url += "&app_id=" + id; url += "&app_code=" + key; + url += "&apiKey=" + key; if (language != null) { url += "&language=" + language; } return url; } - public HereGeocoder(String id, String key, String language, int cacheSize, AddressFormat addressFormat) { - super(formatUrl(id, key, language), cacheSize, addressFormat); + public HereGeocoder( + String url, String id, String key, String language, int cacheSize, AddressFormat addressFormat) { + super(formatUrl(url, id, key, language), cacheSize, addressFormat); } @Override diff --git a/src/test/java/org/traccar/geocoder/GeocoderTest.java b/src/test/java/org/traccar/geocoder/GeocoderTest.java index 85d9bf62f..9f59d0b23 100644 --- a/src/test/java/org/traccar/geocoder/GeocoderTest.java +++ b/src/test/java/org/traccar/geocoder/GeocoderTest.java @@ -73,7 +73,7 @@ public class GeocoderTest { @Ignore @Test public void testHere() { - Geocoder geocoder = new HereGeocoder("", "", null, 0, new AddressFormat()); + Geocoder geocoder = new HereGeocoder(null, "", "", null, 0, new AddressFormat()); String address = geocoder.getAddress(48.8575, 2.2944, null); assertEquals("6 Avenue Gustave Eiffel, Paris, ÃŽle-de-France, FRA", address); } -- cgit v1.2.3 From 720916a476f25f12156cdd7e07cbee4f48d1b1ad Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 21 Jan 2020 22:46:34 -0800 Subject: Implement server response --- .../org/traccar/protocol/BlueProtocolDecoder.java | 33 ++++++++++++++++++++-- .../traccar/protocol/BlueProtocolDecoderTest.java | 3 ++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/BlueProtocolDecoder.java b/src/main/java/org/traccar/protocol/BlueProtocolDecoder.java index 98a8ae565..61edcd101 100644 --- a/src/main/java/org/traccar/protocol/BlueProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/BlueProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2020 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. @@ -16,11 +16,14 @@ 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.DateBuilder; import org.traccar.model.Position; @@ -41,6 +44,28 @@ public class BlueProtocolDecoder extends BaseProtocolDecoder { return negative ? -coordinate : coordinate; } + private void sendResponse(Channel channel, int deviceIndex) { + if (channel != null) { + + ByteBuf response = Unpooled.buffer(); + response.writeByte(0xaa); + response.writeShort(2 + 1 + 1 + 6 + 1); + response.writeByte(0x86); // version + response.writeByte(0); + + response.writeByte(6); // data length + response.writeByte(0xa4); // type + response.writeByte(0); // server index + response.writeByte(deviceIndex); + response.writeByte(0); + response.writeByte(0); + + response.writeByte(Checksum.xor(response.nioBuffer(1, response.writerIndex() - 1))); + + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -66,7 +91,7 @@ public class BlueProtocolDecoder extends BaseProtocolDecoder { int frameEnd = buf.readerIndex() + buf.readUnsignedByte(); int type = buf.readUnsignedByte(); - buf.readUnsignedByte(); // reference id + int index = buf.readUnsignedByte(); buf.readUnsignedByte(); buf.readUnsignedByte(); // flags @@ -102,6 +127,10 @@ public class BlueProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // status 5 buf.readUnsignedByte(); // status 6 + } else if (type == 0x84) { + + sendResponse(channel, index); + } buf.readerIndex(frameEnd); diff --git a/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java index 1d1716238..9f3254824 100644 --- a/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class BlueProtocolDecoderTest extends ProtocolTest { BlueProtocolDecoder decoder = new BlueProtocolDecoder(null); + verifyPosition(decoder, binary( + "aa00550000813f6f840b840380001032000000002001030040008005ee1938113b26f300000000000000140114082833044d27602112030002000000b70000020000000000000000650000001601f4000000000000e4")); + verifyPosition(decoder, binary( "aa0055860080e3e79e0b840f800010320000000020010f0040008005ee197f113b26e800000000000000130c11091a2b005ac7a621120f0002000000b7000002000000000000001a3a0000000001f40000000000003f")); -- cgit v1.2.3 From cdbb912a1552d2e8eb6590dbffb6799ee187b50b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 22 Jan 2020 08:41:12 -0800 Subject: Fix frame decoder --- src/main/java/org/traccar/protocol/BlueProtocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/BlueProtocol.java b/src/main/java/org/traccar/protocol/BlueProtocol.java index 79f0714ec..d5dc5c421 100644 --- a/src/main/java/org/traccar/protocol/BlueProtocol.java +++ b/src/main/java/org/traccar/protocol/BlueProtocol.java @@ -26,7 +26,7 @@ public class BlueProtocol extends BaseProtocol { addServer(new TrackerServer(false, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1, 2, 3, 0)); + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1, 2, -2, 0)); pipeline.addLast(new BlueProtocolDecoder(BlueProtocol.this)); } }); -- cgit v1.2.3 From eb2697434dbbb8c12cad26df94e3a367880ac4db Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 22 Jan 2020 23:52:41 -0800 Subject: Fix frame decoding issues --- src/main/java/org/traccar/protocol/OmnicommFrameDecoder.java | 4 ++-- src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/OmnicommFrameDecoder.java b/src/main/java/org/traccar/protocol/OmnicommFrameDecoder.java index 1caf6ceb9..314f19757 100644 --- a/src/main/java/org/traccar/protocol/OmnicommFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/OmnicommFrameDecoder.java @@ -27,11 +27,11 @@ public class OmnicommFrameDecoder extends BaseFrameDecoder { protected Object decode( ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - if (buf.readableBytes() < 10) { + if (buf.readableBytes() < 6) { return null; } - int endIndex = buf.getUnsignedShortLE(2) + buf.readerIndex() + 6; + int endIndex = buf.getUnsignedShortLE(buf.readerIndex() + 2) + buf.readerIndex() + 6; if (buf.writerIndex() < endIndex) { return null; } diff --git a/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java b/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java index 06c6e24eb..ae21de107 100644 --- a/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java @@ -10,6 +10,10 @@ public class OmnicommFrameDecoderTest extends ProtocolTest { OmnicommFrameDecoder decoder = new OmnicommFrameDecoder(); + verifyFrame( + binary("c08600004566"), + decoder.decode(null, null, binary("c08600004566"))); + verifyFrame( binary("c080080061a61915340100001dec"), decoder.decode(null, null, binary("c080080061a61915340100001dec"))); -- cgit v1.2.3 From 1117d4abe4fe3545f9169b05269363c9655061b1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 Jan 2020 08:49:30 -0800 Subject: Fix logging issue (fix #4473) --- .../java/org/traccar/helper/ServletHelper.java | 26 ++++++++++++++++++---- .../java/org/traccar/helper/ServletHelperTest.java | 13 +++++++++-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/helper/ServletHelper.java b/src/main/java/org/traccar/helper/ServletHelper.java index e3481e249..b6c587ec3 100644 --- a/src/main/java/org/traccar/helper/ServletHelper.java +++ b/src/main/java/org/traccar/helper/ServletHelper.java @@ -1,8 +1,22 @@ +/* + * Copyright 2020 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.helper; import javax.servlet.http.HttpServletRequest; - public final class ServletHelper { private ServletHelper() { @@ -14,10 +28,14 @@ public final class ServletHelper { String remoteAddress = request.getHeader("X-FORWARDED-FOR"); if (remoteAddress != null && !remoteAddress.isEmpty()) { - return remoteAddress.substring(0, remoteAddress.indexOf(",")); // removes the additional data + int separatorIndex = remoteAddress.indexOf(","); + if (separatorIndex > 0) { + return remoteAddress.substring(0, separatorIndex); // remove the additional data + } else { + return remoteAddress; + } } else { - remoteAddress = request.getRemoteAddr(); - return remoteAddress; + return request.getRemoteAddr(); } } else { return null; diff --git a/src/test/java/org/traccar/helper/ServletHelperTest.java b/src/test/java/org/traccar/helper/ServletHelperTest.java index 7359bf3dd..e419b6491 100644 --- a/src/test/java/org/traccar/helper/ServletHelperTest.java +++ b/src/test/java/org/traccar/helper/ServletHelperTest.java @@ -11,7 +11,7 @@ import static org.junit.Assert.assertEquals; public class ServletHelperTest { @Test - public void testIpBehindReverseProxy() { + public void testRetrieveRemoteAddressProxyMultiple() { MockRequest request = new MockRequest(); request.setRemoteAddress("147.120.1.5"); request.addHeader("X-FORWARDED-FOR", "231.23.45.65, 10.20.10.33, 10.20.20.34"); @@ -20,7 +20,16 @@ public class ServletHelperTest { } @Test - public void testNormalIp() { + public void testRetrieveRemoteAddressProxySingle() { + MockRequest request = new MockRequest(); + request.setRemoteAddress("147.120.1.5"); + request.addHeader("X-FORWARDED-FOR", "231.23.45.65"); + + assertEquals("231.23.45.65", ServletHelper.retrieveRemoteAddress(request)); + } + + @Test + public void testRetrieveRemoteAddressNoProxy() { MockRequest request = new MockRequest(); request.setRemoteAddress("231.23.45.65"); -- cgit v1.2.3 From e7866cd4bd5a4552f0d562671ce6a713d18824b8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 24 Jan 2020 19:49:23 -0800 Subject: Support VT600 and VT900 --- src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java | 4 ++-- src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java index cbfc3660a..bd66cdc4b 100644 --- a/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2020 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. @@ -47,7 +47,7 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { } private static final Pattern PATTERN = new PatternBuilder() - .number("(dd)(dd)(dd).?d*,") // time (hhmmss) + .number("(d+)(dd)(dd).?d*,") // time (hhmmss) .expression("([AV]),") // validity .number("(d+)(dd.d+),") // latitude .expression("([NS]),") diff --git a/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java index da5a81144..94f4c8202 100644 --- a/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java @@ -10,6 +10,12 @@ public class MeiligaoProtocolDecoderTest extends ProtocolTest { MeiligaoProtocolDecoder decoder = new MeiligaoProtocolDecoder(null); + verifyPosition(decoder, binary( + "2424011e143190975469ff99993130343634382e3030302c562c303735332e353338332c4e2c30393832322e313737382c452c302e30302c302c3230303132302c2c2a31417c302e307c307c363430307c303030302c303030302c303130312c303238467c30323038303030353137444630304633363838467c30387c30303030314242367c30307c2520205e59454e53414241494348414924534f4e474b52414e244d522e5e5e3f3b363030373634333130303530303337333835333d3135303531393637303631343d3f2b2020202020202020202020202032342020202020202020202020203120202020202020202020202030303034313131202030303130302020202020202020202020202020202020202020203f7b850d0a")); + + verifyPosition(decoder, binary( + "2424008d143190975469ff99993130343634312e3030302c562c303735332e353338332c4e2c30393832322e313737382c452c302e30302c302c3230303132302c2c2a31337c302e307c307c323430307c303030302c303030302c303130302c303238397c30323038303030353137444630304633363838467c30387c30303030314242367c3030be980d0a")); + verifyNull(decoder, binary( "24240012254748594772ff080002ffff0d0a")); -- cgit v1.2.3 From f4134fb1a1749e4556b6fdcfd539d4e8a78a2e93 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 24 Jan 2020 21:29:46 -0800 Subject: Support engine data --- .../protocol/PacificTrackProtocolDecoder.java | 54 ++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PacificTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/PacificTrackProtocolDecoder.java index 15e08d7b1..d49a73a86 100644 --- a/src/main/java/org/traccar/protocol/PacificTrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PacificTrackProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2020 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. @@ -63,7 +63,7 @@ public class PacificTrackProtocolDecoder extends BaseProtocolDecoder { while (buf.isReadable()) { int segmentId = readBitExt(buf); - int segmentLength = readBitExt(buf); + int segmentEnd = readBitExt(buf) + buf.readerIndex(); switch (segmentId) { case 0x01: @@ -83,12 +83,60 @@ public class PacificTrackProtocolDecoder extends BaseProtocolDecoder { position.setSpeed(UnitsConverter.knotsFromKph(BitUtil.to(speedAndCourse, 12) * 0.1)); position.set(Position.KEY_INDEX, buf.readUnsignedShort()); break; + case 0x92: + while (buf.readerIndex() < segmentEnd) { + int field = buf.readUnsignedByte(); + int fieldPrefix = BitUtil.from(field, 5); + if (fieldPrefix < 0b100) { + switch (BitUtil.between(field, 2, 5)) { + case 0b000: + position.set("bus", BitUtil.to(field, 2)); + case 0b001: + position.set("currentGear", BitUtil.to(field, 2)); + break; + default: + break; + } + } else if (fieldPrefix < 0b101) { + switch (BitUtil.to(field, 5)) { + case 0b00000: + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte()); + break; + case 0b00001: + position.set(Position.KEY_RPM, buf.readUnsignedByte() * 32); + break; + default: + buf.readUnsignedByte(); + break; + } + } else if (fieldPrefix < 0b110) { + buf.readUnsignedShort(); + } else if (fieldPrefix < 0b111) { + switch (BitUtil.to(field, 5)) { + case 0b00000: + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100); + break; + case 0b00001: + position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 180); + break; + case 0b00010: + position.set("idleHours", buf.readUnsignedInt() * 180); + break; + default: + buf.readUnsignedInt(); + break; + } + } else { + buf.skipBytes(buf.readUnsignedByte()); + } + } + break; case 0x100: String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(0, 15); deviceSession = getDeviceSession(channel, remoteAddress, imei); break; default: - buf.skipBytes(segmentLength); + buf.readerIndex(segmentEnd); break; } } -- cgit v1.2.3 From a9855cd2df5e364c66bb419eb0ab7fb4d66f2643 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 24 Jan 2020 21:32:41 -0800 Subject: Decode fuel data --- src/main/java/org/traccar/protocol/BceProtocolDecoder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java index 30f9bb1f3..c71cdffd9 100644 --- a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java @@ -83,10 +83,10 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { buf.skipBytes(4); } if (BitUtil.check(mask, 12)) { - buf.skipBytes(2); + position.set("fuel1", buf.readUnsignedShort()); } if (BitUtil.check(mask, 13)) { - buf.skipBytes(2); + position.set("fuel2", buf.readUnsignedShort()); } if (BitUtil.check(mask, 14)) { -- cgit v1.2.3 From c8198d40db6e623ee45eff121cdf8cfaa2d58281 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 25 Jan 2020 09:47:45 -0800 Subject: Support driver license --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 8 ++++++++ src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index c435b6cec..946652b03 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -730,6 +730,14 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { decodeStatus(position, buf); } + if (type == MSG_GPS_LBS_1 && buf.readableBytes() > 75 + 6) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + String data = buf.readCharSequence(buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString(); + buf.readUnsignedByte(); // alarm + buf.readUnsignedByte(); // swiped + position.set("driverLicense", data.trim()); + } + if (type == MSG_GPS_LBS_1 && buf.readableBytes() == 2 + 6) { int mask = buf.readUnsignedShort(); position.set(Position.KEY_IGNITION, BitUtil.check(mask, 8 + 7)); diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index fd5d55a50..672711f22 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,9 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttributes(decoder, binary( + "7878711213081f081d0fc6017ba3fa0ac62a923e550e02080503f300b26d000000004b20202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202030300017c7470d0a")); + verifyAttributes(decoder, binary( "797900B2700000000102003500010400330012000000000000000000000000000000000000003400061354A48DFF00003400061154A48E56000011000A000000000000000000000001000803537601000282180002000802140743044211890003000A89340752000038689636001800020182002B000116002C000454A4FF350009000100000A0001010028000100002E000400000000002A00010000290004000000000030000A000101680014016802D00000B38F0D0A")); -- cgit v1.2.3 From 2d5a5e600e576cd4e31046be104cc98f799ad091 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 26 Jan 2020 21:24:14 -0800 Subject: Decode BLE location --- .../java/org/traccar/protocol/Minifinder2ProtocolDecoder.java | 9 +++++++++ .../org/traccar/protocol/Minifinder2ProtocolDecoderTest.java | 3 +++ 2 files changed, 12 insertions(+) diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index b6f257d2c..b8ab134c5 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -154,6 +154,15 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { mac.substring(0, mac.length() - 1), rssi)); } break; + case 0x23: + if (endIndex > buf.readerIndex()) { + buf.skipBytes(6); // mac + } + if (endIndex > buf.readerIndex()) { + position.setLatitude(buf.readIntLE() * 0.0000001); + position.setLongitude(buf.readIntLE() * 0.0000001); + } + break; case 0x24: position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); long status = buf.readUnsignedIntLE(); diff --git a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java index c0ce67cb6..5898b74a8 100644 --- a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java @@ -13,6 +13,9 @@ public class Minifinder2ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "ab10150076f1320003100133353534363530373130323933303602105a")); + verifyNotNull(decoder, binary( + "ab1024009b3f9742011001383635323039303336333430303235113154cfc95d0a00000080d0c95d0a000000")); + verifyPosition(decoder, binary( "ab103f007e2533000110013335353436353037313032393330360930e09d245d210100000924b49e245d01025b201620e6c03b1ef367420400000000aa026d00c90e0000100110")); -- cgit v1.2.3 From 7113e04b9a5cabb509ff0219da18098f4b55924f Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Thu, 30 Jan 2020 03:49:55 -0500 Subject: Changes after review --- src/main/java/org/traccar/WebDataHandler.java | 69 +++++++++++++-------------- src/main/java/org/traccar/config/Keys.java | 9 ++-- 2 files changed, 36 insertions(+), 42 deletions(-) diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java index 19c5a58a8..2d6d98f5d 100644 --- a/src/main/java/org/traccar/WebDataHandler.java +++ b/src/main/java/org/traccar/WebDataHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2020 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. @@ -18,6 +18,9 @@ package org.traccar; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.channel.ChannelHandler; +import io.netty.util.Timeout; +import io.netty.util.TimerTask; + import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.IdentityManager; @@ -41,6 +44,7 @@ import java.util.Calendar; import java.util.Formatter; import java.util.Locale; import java.util.TimeZone; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @ChannelHandler.Sharable @@ -57,12 +61,11 @@ public class WebDataHandler extends BaseDataHandler { private final String header; private final boolean json; - private final Boolean retryEnabled; - private final Integer retryDelayMin; - private final Integer retryDelayMax; - private final Integer deliveryPendingLimit; + private final boolean retryEnabled; + private final int retryDelayMin; + private final int retryDelayMax; + private final int deliveryPendingLimit; - private AtomicInteger deliveryFaliuresInRow; private AtomicInteger deliveryPendingCurrent; @Inject @@ -77,17 +80,10 @@ public class WebDataHandler extends BaseDataHandler { this.json = config.getBoolean(Keys.FORWARD_JSON); this.retryEnabled = config.getBoolean(Keys.FORWARD_RETRY_ENABLE); + this.retryDelayMin = config.getInteger(Keys.FORWARD_RETRY_DELAY_MIN, 1); + this.retryDelayMax = config.getInteger(Keys.FORWARD_RETRY_DELAY_MAX, 10); + this.deliveryPendingLimit = config.getInteger(Keys.FORWARD_RETRY_PENDING_LIMIT, 100); - Integer retryDelayMin = config.getInteger(Keys.FORWARD_RETRY_DELAY_MIN, 1); - this.retryDelayMin = (retryDelayMin > 0 && retryDelayMin < 3600) ? retryDelayMin : 1; - - Integer retryDelayMax = config.getInteger(Keys.FORWARD_RETRY_DELAY_MAX, 10); - this.retryDelayMax = (retryDelayMax > retryDelayMin && retryDelayMax < 3600) ? retryDelayMax : retryDelayMin; - - Integer deliveryPendingLimit = config.getInteger(Keys.FORWARD_RETRY_PENDING_LIMIT, 100); - this.deliveryPendingLimit = (retryDelayMax > 0) ? deliveryPendingLimit : 100; - - this.deliveryFaliuresInRow = new AtomicInteger(0); this.deliveryPendingCurrent = new AtomicInteger(0); } @@ -183,15 +179,15 @@ public class WebDataHandler extends BaseDataHandler { class AsyncRequestAndCallback implements InvocationCallback { - private Integer delay = retryDelayMin; - private Map jsonPayload; + private int delay = retryDelayMin; + private Map payload; private Invocation.Builder requestBuilder; AsyncRequestAndCallback(Position position) { String formattedUrl; try { - formattedUrl = (json) ? url : formatRequest(position); + formattedUrl = json ? url : formatRequest(position); } catch (UnsupportedEncodingException | JsonProcessingException e) { throw new RuntimeException("Forwarding formatting error", e); } @@ -205,7 +201,7 @@ public class WebDataHandler extends BaseDataHandler { } if (json) { - jsonPayload = prepareJsonPayload(position); + payload = prepareJsonPayload(position); } deliveryPendingCurrent.incrementAndGet(); @@ -215,7 +211,7 @@ public class WebDataHandler extends BaseDataHandler { private void send() { if (json) { - requestBuilder.async().post(Entity.json(jsonPayload), this); + requestBuilder.async().post(Entity.json(payload), this); } else { requestBuilder.async().get(this); } @@ -223,36 +219,35 @@ public class WebDataHandler extends BaseDataHandler { private void retry() { try { - deliveryFaliuresInRow.incrementAndGet(); - if (!retryEnabled || deliveryPendingCurrent.get() > deliveryPendingLimit) { - deliveryPendingCurrent.decrementAndGet(); - } else { - Integer i = 0; - for ( ; i < delay; i++) { - Thread.sleep(1000); - if (deliveryFaliuresInRow.get() == 0) { - delay = retryDelayMin; - break; + if (retryEnabled && deliveryPendingCurrent.get() <= deliveryPendingLimit) { + GlobalTimer.getTimer().newTimeout(new TimerTask() { + @Override + public void run(Timeout timeout) { + if (!timeout.isCancelled()) { + if (delay < retryDelayMax) { + delay++; + } + send(); + } } - } - if (i >= delay && delay < retryDelayMax) { - delay++; - } - send(); + }, delay, TimeUnit.SECONDS); + return; } } catch (Exception e) { } + deliveryPendingCurrent.decrementAndGet(); } + @Override public void completed(Response response) { if (response.getStatus() == 200) { - deliveryFaliuresInRow.set(0); deliveryPendingCurrent.decrementAndGet(); } else { retry(); } } + @Override public void failed(Throwable throwable) { retry(); } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index ec4eb1801..999a1d6df 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -104,23 +104,22 @@ public final class Keys { * Position forwarding retrying enable. When enabled, additional attempts are made to deliver positions. * If initial delivery fails, because of an unreachable server or an HTTP response different from '200 OK', * the software waits for 'forward.retry.delay.min' seconds to retry delivery. On subsequent failures, this - * delay is incremented by 1 second up to 'forward.retry.delay.max'. On successful delivery, the delay is reset - * to 'forward.retry.delay.min'. Pending positions to be delivered are limited to 'forward.retry.pending.limit'. - * If this limit is reached, positions are discarded before next retry. + * delay is incremented by 1 second up to 'forward.retry.delay.max'. Positions pending to be delivered + * are limited to 'forward.retry.pending.limit'. If this limit is reached, positions get discarded. */ public static final ConfigKey FORWARD_RETRY_ENABLE = new ConfigKey( "forward.retry.enable", Boolean.class); /** * Position forwarding retry minimum delay in seconds. - * Can be set to anything between 1 and 3600 seconds. Defaults to 1 second. + * Can be set to anything greater than 0. Defaults to 1 second. */ public static final ConfigKey FORWARD_RETRY_DELAY_MIN = new ConfigKey( "forward.retry.delay.min", Integer.class); /** * Position forwarding retry maximum delay in seconds. - * Can be set to anything between 1 and 3600 seconds. Defaults to 10 seconds. + * Can be set to anything greater than 0. Defaults to 10 seconds. */ public static final ConfigKey FORWARD_RETRY_DELAY_MAX = new ConfigKey( "forward.retry.delay.max", Integer.class); -- cgit v1.2.3 From 3c71ac47b4515fb799e67a18b18d722bea4d2241 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Thu, 30 Jan 2020 05:33:24 -0500 Subject: Log position forwarding failures --- src/main/java/org/traccar/WebDataHandler.java | 36 +++++++++++++++++++-------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java index 2d6d98f5d..e2f7c1e8b 100644 --- a/src/main/java/org/traccar/WebDataHandler.java +++ b/src/main/java/org/traccar/WebDataHandler.java @@ -20,6 +20,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.channel.ChannelHandler; import io.netty.util.Timeout; import io.netty.util.TimerTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; @@ -53,6 +55,8 @@ public class WebDataHandler extends BaseDataHandler { private static final String KEY_POSITION = "position"; private static final String KEY_DEVICE = "device"; + private static final Logger LOGGER = LoggerFactory.getLogger(WebDataHandler.class); + private final IdentityManager identityManager; private final ObjectMapper objectMapper; private final Client client; @@ -219,19 +223,29 @@ public class WebDataHandler extends BaseDataHandler { private void retry() { try { - if (retryEnabled && deliveryPendingCurrent.get() <= deliveryPendingLimit) { - GlobalTimer.getTimer().newTimeout(new TimerTask() { - @Override - public void run(Timeout timeout) { - if (!timeout.isCancelled()) { - if (delay < retryDelayMax) { - delay++; + String message = "Position forwarding failed."; + if (!retryEnabled) { + LOGGER.warn(message); + } else { + int pending = deliveryPendingCurrent.get(); + if (pending <= deliveryPendingLimit) { + LOGGER.warn(message + " Pending: " + pending + + ". Retrying in " + delay + " seconds."); + GlobalTimer.getTimer().newTimeout(new TimerTask() { + @Override + public void run(Timeout timeout) { + if (!timeout.isCancelled()) { + if (delay < retryDelayMax) { + delay++; + } + send(); } - send(); } - } - }, delay, TimeUnit.SECONDS); - return; + }, delay, TimeUnit.SECONDS); + return; + } + LOGGER.warn(message + " Pending: " + pending + + ". Delivery will not be retried."); } } catch (Exception e) { } -- cgit v1.2.3 From 3bf277a340c57c485af7f3c0ab46b27e070b0998 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 30 Jan 2020 22:16:59 -0800 Subject: Add new RST test case --- src/main/java/org/traccar/protocol/RstProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java index 8981c117b..05601ed51 100644 --- a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2020 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. diff --git a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java index 66286776a..fb6dca3e6 100644 --- a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class RstProtocolDecoderTest extends ProtocolTest { RstProtocolDecoder decoder = new RstProtocolDecoder(null); + verifyPosition(decoder, text( + "RST;L;RST-MINIv2;V7.02;008068078;61;1;27-01-2020 21:36:33;27-01-2020 21:36:33;-16.696159;-49.284275;0;67;786;1;15;0;00;B0;00;19;06;12.42;4.16;79;20;FE;0000;01;E0;00800020;0;467;FIM;")); + verifyAttribute(decoder, text( "RST;A;RST-MINIv2;V7.00;008033985;1;7;30-08-2019 11:31:38;30-08-2019 11:31:15;-23.645868;-46.637741;0;226;828;0;10;0;00;20;00;1A;02;0.02;3.40;0;0;FE;0000;04;80;11;0;FIM;"), Position.KEY_BATTERY, 3.40); -- cgit v1.2.3 From c00fd59ecf8739e47a4f2460bbb4802f4cead1a1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 30 Jan 2020 22:37:36 -0800 Subject: Decode cell towers info --- .../org/traccar/protocol/HuaShengProtocolDecoder.java | 16 +++++++++++++++- .../traccar/protocol/HuaShengProtocolDecoderTest.java | 3 +++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java index 9449e2d5c..920898039 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2020 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. @@ -25,6 +25,8 @@ import org.traccar.Protocol; import org.traccar.helper.BitUtil; import org.traccar.helper.DateBuilder; import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; import org.traccar.model.Position; import java.net.SocketAddress; @@ -161,6 +163,18 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { position.set( Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); break; + case 0x0020: + Network network = new Network(); + String[] cells = buf.readCharSequence( + length, StandardCharsets.US_ASCII).toString().split("\\+"); + for (String cell : cells) { + String[] values = cell.split("@"); + network.addCellTower(CellTower.from( + Integer.parseInt(values[0]), Integer.parseInt(values[1]), + Integer.parseInt(values[2], 16), Integer.parseInt(values[3], 16))); + } + position.setNetwork(network); + break; default: buf.skipBytes(length); break; diff --git a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java index 6033bc744..b624f69ab 100644 --- a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java @@ -16,6 +16,9 @@ public class HuaShengProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "c000000077aa0200000000000e000100143347315f48312e315f56312e30372e54000300133335353835353035303434303635380004000b3531323030303000050005010006000400070004000800050000090018383936313032353431343533333239313833360d000a000f796573696e7465726e6574c0")); + verifyNotNull(decoder, binary( + "c000000077aa00000000000070020000003230303132373035313635330000000000000000000000000000000000010015ffffffff000000000000019dffffffffff0005000a1f00000e455a00200019313238354031406666666540386233663930634030000f0013333536373236313038313335343530c0")); + verifyPosition(decoder, binary( "c000000060aa000000000000fa8000000031393037303431363434323700e9900affd61c1b00000000003a000000010015ffffff0000000000000004c2ffffffffff0005000a0d080000ca6a000900155741555a5a5a344730454e313133373233c0")); -- cgit v1.2.3 From fdf16e5ee51cf7537920d04e1fd4bffbdbd5fa42 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 31 Jan 2020 22:53:51 -0800 Subject: Respond with original length --- .../java/org/traccar/protocol/TopinProtocolDecoder.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java index ea72b7cb8..0f22bc7fd 100644 --- a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2020 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,11 +44,11 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_WIFI_OFFLINE = 0x17; public static final int MSG_WIFI = 0x69; - private void sendResponse(Channel channel, int type, ByteBuf content) { + private void sendResponse(Channel channel, int length, int type, ByteBuf content) { if (channel != null) { ByteBuf response = Unpooled.buffer(); response.writeShort(0x7878); - response.writeByte(1 + content.readableBytes()); + response.writeByte(length); response.writeByte(type); response.writeBytes(content); response.writeByte('\r'); @@ -75,7 +75,7 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { deviceSession = getDeviceSession(channel, remoteAddress, imei); ByteBuf content = Unpooled.buffer(); content.writeByte(deviceSession != null ? 0x01 : 0x44); - sendResponse(channel, type, content); + sendResponse(channel, length, type, content); return null; } else { deviceSession = getDeviceSession(channel, remoteAddress); @@ -95,7 +95,7 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { ByteBuf content = Unpooled.buffer(); content.writeBytes(time); - sendResponse(channel, type, content); + sendResponse(channel, length, type, content); return position; @@ -127,7 +127,7 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { if (length >= 7) { content.writeByte(signal); } - sendResponse(channel, type, content); + sendResponse(channel, length, type, content); return position; @@ -160,7 +160,7 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { ByteBuf content = Unpooled.buffer(); content.writeBytes(time); - sendResponse(channel, type, content); + sendResponse(channel, length, type, content); return position; -- cgit v1.2.3 From 230227fde27da2db785d97c6894160b256ad6c10 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Feb 2020 21:35:24 -0800 Subject: Decode device time --- .../java/org/traccar/protocol/TopinProtocolDecoder.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java index 0f22bc7fd..eee0e9ae8 100644 --- a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java @@ -23,6 +23,8 @@ import org.traccar.BaseProtocolDecoder; import org.traccar.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; +import org.traccar.helper.BcdUtil; +import org.traccar.helper.DateBuilder; import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; @@ -136,9 +138,17 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - getLastLocation(position, null); - ByteBuf time = buf.readSlice(6); + DateBuilder dateBuilder = new DateBuilder() + .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)); + time.resetReaderIndex(); + + getLastLocation(position, dateBuilder.getDate()); Network network = new Network(); for (int i = 0; i < length; i++) { -- cgit v1.2.3 From 75e5eded6c877577044e9db22cae255cac8d04a1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 2 Feb 2020 15:07:56 -0800 Subject: Move files to new locations --- .../handler/protocol/Arnavi4FrameDecoder.java | 74 --------- .../traccar/handler/protocol/Arnavi4Protocol.java | 45 ----- .../handler/protocol/Arnavi4ProtocolDecoder.java | 182 --------------------- .../org/traccar/protocol/Arnavi4FrameDecoder.java | 74 +++++++++ .../java/org/traccar/protocol/Arnavi4Protocol.java | 45 +++++ .../traccar/protocol/Arnavi4ProtocolDecoder.java | 182 +++++++++++++++++++++ .../handler/protocol/Arnavi4FrameDecoderTest.java | 50 ------ .../protocol/Arnavi4ProtocolDecoderTest.java | 40 ----- .../traccar/protocol/Arnavi4FrameDecoderTest.java | 50 ++++++ .../protocol/Arnavi4ProtocolDecoderTest.java | 40 +++++ 10 files changed, 391 insertions(+), 391 deletions(-) delete mode 100644 src/main/java/org/traccar/handler/protocol/Arnavi4FrameDecoder.java delete mode 100644 src/main/java/org/traccar/handler/protocol/Arnavi4Protocol.java delete mode 100644 src/main/java/org/traccar/handler/protocol/Arnavi4ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Arnavi4Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java delete mode 100644 src/test/java/org/traccar/handler/protocol/Arnavi4FrameDecoderTest.java delete mode 100644 src/test/java/org/traccar/handler/protocol/Arnavi4ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java diff --git a/src/main/java/org/traccar/handler/protocol/Arnavi4FrameDecoder.java b/src/main/java/org/traccar/handler/protocol/Arnavi4FrameDecoder.java deleted file mode 100644 index b13f3fd7d..000000000 --- a/src/main/java/org/traccar/handler/protocol/Arnavi4FrameDecoder.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2017 Ivan Muratov (binakot@gmail.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.traccar.protocol; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.handler.codec.frame.FrameDecoder; - -public class Arnavi4FrameDecoder extends FrameDecoder { - - private static final int MIN_LENGTH = 4; - private static final int HEADER_LENGTH = 10; - private static final int PACKET_WRAPPER_LENGTH = 8; - private static final int COMMAND_ANSWER_PACKET_LENGTH = 4; - private static final int COMMAND_ANSWER_PARCEL_NUMBER = 0xfd; - private static final byte PACKAGE_END_SIGN = 0x5d; - - private boolean firstPacket = true; - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception { - - if (buf.readableBytes() < MIN_LENGTH) { - return null; - } - - int length; - if (firstPacket) { - firstPacket = false; - length = HEADER_LENGTH; - } else { - int index = buf.getUnsignedByte(1); // parcel number - if (index == COMMAND_ANSWER_PARCEL_NUMBER) { - length = COMMAND_ANSWER_PACKET_LENGTH; - } else { - int pos = 2; // start sign + parcel number - while (pos + PACKET_WRAPPER_LENGTH < buf.readableBytes() - && buf.getByte(pos) != PACKAGE_END_SIGN) { - - int dataLength = buf.getUnsignedShort(pos + 1); - pos += PACKET_WRAPPER_LENGTH + dataLength; // packet type + data length + unixtime + data + crc - } - - if (buf.getByte(pos) != PACKAGE_END_SIGN) { // end sign - return null; - } - - length = pos + 1; - } - } - - if (buf.readableBytes() >= length) { - return buf.readBytes(length); - } - - return null; - } - -} diff --git a/src/main/java/org/traccar/handler/protocol/Arnavi4Protocol.java b/src/main/java/org/traccar/handler/protocol/Arnavi4Protocol.java deleted file mode 100644 index 381a9b457..000000000 --- a/src/main/java/org/traccar/handler/protocol/Arnavi4Protocol.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2017 Ivan Muratov (binakot@gmail.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.traccar.protocol; - -import org.jboss.netty.bootstrap.ServerBootstrap; -import org.jboss.netty.channel.ChannelPipeline; -import org.traccar.BaseProtocol; -import org.traccar.TrackerServer; - -import java.nio.ByteOrder; -import java.util.List; - -public class Arnavi4Protocol extends BaseProtocol { - - public Arnavi4Protocol() { - super("arnavi4"); - } - - @Override - public void initTrackerServers(List serverList) { - TrackerServer server = new TrackerServer(new ServerBootstrap(), getName()) { - @Override - protected void addSpecificHandlers(ChannelPipeline pipeline) { - pipeline.addLast("frameDecoder", new Arnavi4FrameDecoder()); - pipeline.addLast("objectDecoder", new Arnavi4ProtocolDecoder(Arnavi4Protocol.this)); - } - }; - server.setEndianness(ByteOrder.LITTLE_ENDIAN); - serverList.add(server); - } - -} diff --git a/src/main/java/org/traccar/handler/protocol/Arnavi4ProtocolDecoder.java b/src/main/java/org/traccar/handler/protocol/Arnavi4ProtocolDecoder.java deleted file mode 100644 index 06abb563f..000000000 --- a/src/main/java/org/traccar/handler/protocol/Arnavi4ProtocolDecoder.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2017 Ivan Muratov (binakot@gmail.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.traccar.protocol; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.helper.Checksum; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { - - private static final byte HEADER_START_SIGN = (byte) 0xff; - private static final byte HEADER_VERSION_1 = 0x22; - private static final byte HEADER_VERSION_2 = 0x23; - - private static final byte RECORD_PING = 0x00; - private static final byte RECORD_DATA = 0x01; - private static final byte RECORD_TEXT = 0x03; - private static final byte RECORD_FILE = 0x04; - private static final byte RECORD_BINARY = 0x06; - - private static final byte TAG_LATITUDE = 3; - private static final byte TAG_LONGITUDE = 4; - private static final byte TAG_COORD_PARAMS = 5; - - public Arnavi4ProtocolDecoder(Arnavi4Protocol protocol) { - super(protocol); - } - - private void sendResponse(Channel channel, byte version, int index) { - if (channel != null) { - final ChannelBuffer response; - if (version == HEADER_VERSION_1) { - response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 4); - response.writeByte(0x7b); - response.writeByte(0x00); - response.writeByte((byte) index); - response.writeByte(0x7d); - } else if (version == HEADER_VERSION_2) { - response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 9); - response.writeByte(0x7b); - response.writeByte(0x04); - response.writeByte(0x00); - byte[] timeBytes = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)).array(); - response.writeByte(Checksum.modulo256(timeBytes)); - response.writeBytes(timeBytes); - response.writeByte(0x7d); - } else { - return; // Ignore unsupported header's versions - } - channel.write(response); - } - } - - private Position decodePosition(DeviceSession deviceSession, ChannelBuffer buf, int length, Date time) { - - final Position position = new Position(); - position.setProtocol(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(time); - - int readBytes = 0; - while (readBytes < length) { - short tag = buf.readUnsignedByte(); - switch (tag) { - case TAG_LATITUDE: - position.setLatitude(buf.readFloat()); - position.setValid(true); - break; - - case TAG_LONGITUDE: - position.setLongitude(buf.readFloat()); - position.setValid(true); - break; - - case TAG_COORD_PARAMS: - position.setCourse(buf.readUnsignedByte() * 2); - position.setAltitude(buf.readUnsignedByte() * 10); - byte satellites = buf.readByte(); - position.set(Position.KEY_SATELLITES, satellites & 0x0F + (satellites >> 4) & 0x0F); // gps+glonass - position.setSpeed(buf.readUnsignedByte()); - break; - - default: - buf.readBytes(4); // Skip unsupported tags - break; - } - - readBytes += 5; // 1 byte tag + 4 bytes value - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ChannelBuffer buf = (ChannelBuffer) msg; - - byte startSign = buf.readByte(); - - if (startSign == HEADER_START_SIGN) { - - byte version = buf.readByte(); - - String imei = String.valueOf(buf.readLong()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - - if (deviceSession != null) { - sendResponse(channel, version, 0); - } - - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - int index = buf.readUnsignedByte(); - - byte recordType = buf.readByte(); - while (buf.readableBytes() > 0) { - switch (recordType) { - case RECORD_PING: - case RECORD_DATA: - case RECORD_TEXT: - case RECORD_FILE: - case RECORD_BINARY: - int length = buf.readUnsignedShort(); - Date time = new Date(buf.readUnsignedInt() * 1000); - - if (recordType == RECORD_DATA) { - positions.add(decodePosition(deviceSession, buf, length, time)); - } else { - buf.readBytes(length); // Skip other types of record - } - - buf.readUnsignedByte(); // crc - break; - - default: - return null; // Ignore unsupported types of record - } - - recordType = buf.readByte(); - } - - sendResponse(channel, HEADER_VERSION_1, index); - - return positions; - } - -} diff --git a/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java new file mode 100644 index 000000000..b13f3fd7d --- /dev/null +++ b/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java @@ -0,0 +1,74 @@ +/* + * Copyright 2017 Ivan Muratov (binakot@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.handler.codec.frame.FrameDecoder; + +public class Arnavi4FrameDecoder extends FrameDecoder { + + private static final int MIN_LENGTH = 4; + private static final int HEADER_LENGTH = 10; + private static final int PACKET_WRAPPER_LENGTH = 8; + private static final int COMMAND_ANSWER_PACKET_LENGTH = 4; + private static final int COMMAND_ANSWER_PARCEL_NUMBER = 0xfd; + private static final byte PACKAGE_END_SIGN = 0x5d; + + private boolean firstPacket = true; + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception { + + if (buf.readableBytes() < MIN_LENGTH) { + return null; + } + + int length; + if (firstPacket) { + firstPacket = false; + length = HEADER_LENGTH; + } else { + int index = buf.getUnsignedByte(1); // parcel number + if (index == COMMAND_ANSWER_PARCEL_NUMBER) { + length = COMMAND_ANSWER_PACKET_LENGTH; + } else { + int pos = 2; // start sign + parcel number + while (pos + PACKET_WRAPPER_LENGTH < buf.readableBytes() + && buf.getByte(pos) != PACKAGE_END_SIGN) { + + int dataLength = buf.getUnsignedShort(pos + 1); + pos += PACKET_WRAPPER_LENGTH + dataLength; // packet type + data length + unixtime + data + crc + } + + if (buf.getByte(pos) != PACKAGE_END_SIGN) { // end sign + return null; + } + + length = pos + 1; + } + } + + if (buf.readableBytes() >= length) { + return buf.readBytes(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Arnavi4Protocol.java b/src/main/java/org/traccar/protocol/Arnavi4Protocol.java new file mode 100644 index 000000000..381a9b457 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Arnavi4Protocol.java @@ -0,0 +1,45 @@ +/* + * Copyright 2017 Ivan Muratov (binakot@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import org.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.ChannelPipeline; +import org.traccar.BaseProtocol; +import org.traccar.TrackerServer; + +import java.nio.ByteOrder; +import java.util.List; + +public class Arnavi4Protocol extends BaseProtocol { + + public Arnavi4Protocol() { + super("arnavi4"); + } + + @Override + public void initTrackerServers(List serverList) { + TrackerServer server = new TrackerServer(new ServerBootstrap(), getName()) { + @Override + protected void addSpecificHandlers(ChannelPipeline pipeline) { + pipeline.addLast("frameDecoder", new Arnavi4FrameDecoder()); + pipeline.addLast("objectDecoder", new Arnavi4ProtocolDecoder(Arnavi4Protocol.this)); + } + }; + server.setEndianness(ByteOrder.LITTLE_ENDIAN); + serverList.add(server); + } + +} diff --git a/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java new file mode 100644 index 000000000..06abb563f --- /dev/null +++ b/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -0,0 +1,182 @@ +/* + * Copyright 2017 Ivan Muratov (binakot@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.helper.Checksum; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { + + private static final byte HEADER_START_SIGN = (byte) 0xff; + private static final byte HEADER_VERSION_1 = 0x22; + private static final byte HEADER_VERSION_2 = 0x23; + + private static final byte RECORD_PING = 0x00; + private static final byte RECORD_DATA = 0x01; + private static final byte RECORD_TEXT = 0x03; + private static final byte RECORD_FILE = 0x04; + private static final byte RECORD_BINARY = 0x06; + + private static final byte TAG_LATITUDE = 3; + private static final byte TAG_LONGITUDE = 4; + private static final byte TAG_COORD_PARAMS = 5; + + public Arnavi4ProtocolDecoder(Arnavi4Protocol protocol) { + super(protocol); + } + + private void sendResponse(Channel channel, byte version, int index) { + if (channel != null) { + final ChannelBuffer response; + if (version == HEADER_VERSION_1) { + response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 4); + response.writeByte(0x7b); + response.writeByte(0x00); + response.writeByte((byte) index); + response.writeByte(0x7d); + } else if (version == HEADER_VERSION_2) { + response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 9); + response.writeByte(0x7b); + response.writeByte(0x04); + response.writeByte(0x00); + byte[] timeBytes = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)).array(); + response.writeByte(Checksum.modulo256(timeBytes)); + response.writeBytes(timeBytes); + response.writeByte(0x7d); + } else { + return; // Ignore unsupported header's versions + } + channel.write(response); + } + } + + private Position decodePosition(DeviceSession deviceSession, ChannelBuffer buf, int length, Date time) { + + final Position position = new Position(); + position.setProtocol(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(time); + + int readBytes = 0; + while (readBytes < length) { + short tag = buf.readUnsignedByte(); + switch (tag) { + case TAG_LATITUDE: + position.setLatitude(buf.readFloat()); + position.setValid(true); + break; + + case TAG_LONGITUDE: + position.setLongitude(buf.readFloat()); + position.setValid(true); + break; + + case TAG_COORD_PARAMS: + position.setCourse(buf.readUnsignedByte() * 2); + position.setAltitude(buf.readUnsignedByte() * 10); + byte satellites = buf.readByte(); + position.set(Position.KEY_SATELLITES, satellites & 0x0F + (satellites >> 4) & 0x0F); // gps+glonass + position.setSpeed(buf.readUnsignedByte()); + break; + + default: + buf.readBytes(4); // Skip unsupported tags + break; + } + + readBytes += 5; // 1 byte tag + 4 bytes value + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ChannelBuffer buf = (ChannelBuffer) msg; + + byte startSign = buf.readByte(); + + if (startSign == HEADER_START_SIGN) { + + byte version = buf.readByte(); + + String imei = String.valueOf(buf.readLong()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + + if (deviceSession != null) { + sendResponse(channel, version, 0); + } + + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + int index = buf.readUnsignedByte(); + + byte recordType = buf.readByte(); + while (buf.readableBytes() > 0) { + switch (recordType) { + case RECORD_PING: + case RECORD_DATA: + case RECORD_TEXT: + case RECORD_FILE: + case RECORD_BINARY: + int length = buf.readUnsignedShort(); + Date time = new Date(buf.readUnsignedInt() * 1000); + + if (recordType == RECORD_DATA) { + positions.add(decodePosition(deviceSession, buf, length, time)); + } else { + buf.readBytes(length); // Skip other types of record + } + + buf.readUnsignedByte(); // crc + break; + + default: + return null; // Ignore unsupported types of record + } + + recordType = buf.readByte(); + } + + sendResponse(channel, HEADER_VERSION_1, index); + + return positions; + } + +} diff --git a/src/test/java/org/traccar/handler/protocol/Arnavi4FrameDecoderTest.java b/src/test/java/org/traccar/handler/protocol/Arnavi4FrameDecoderTest.java deleted file mode 100644 index b634f0cdc..000000000 --- a/src/test/java/org/traccar/handler/protocol/Arnavi4FrameDecoderTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.traccar.protocol; - -import org.junit.Assert; -import org.junit.Test; -import org.traccar.ProtocolTest; - -import java.nio.ByteOrder; - -public class Arnavi4FrameDecoderTest extends ProtocolTest { - - @Test - public void testDecodeValidPackets() throws Exception { - - Arnavi4FrameDecoder decoder = new Arnavi4FrameDecoder(); - - Assert.assertEquals( // Valid HEADER v1 packet with IMEI - binary(ByteOrder.LITTLE_ENDIAN, "ff22f30c45f5c90f0300"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "ff22f30c45f5c90f0300"))); - - Assert.assertEquals( // Valid PACKAGE with one DATA packet - binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); - - Assert.assertEquals( // Valid PACKAGE with two DATA packet - binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); - - Assert.assertEquals( // Valid PACKAGE with one TEXT packet. - binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b5d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b5d"))); - - Assert.assertEquals( // Valid PACKAGE with two TEXT packet. - binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"))); - - Assert.assertEquals( // Valid PACKAGE with one BINARY packet. - binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); - - Assert.assertEquals( // Valid PACKAGE with two BINARY packet. - binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); - - Assert.assertEquals( // Valid PACKAGE with answer to server on file transfer - binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"))); - - } - -} \ No newline at end of file diff --git a/src/test/java/org/traccar/handler/protocol/Arnavi4ProtocolDecoderTest.java b/src/test/java/org/traccar/handler/protocol/Arnavi4ProtocolDecoderTest.java deleted file mode 100644 index d789b1c9c..000000000 --- a/src/test/java/org/traccar/handler/protocol/Arnavi4ProtocolDecoderTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.traccar.protocol; - -import org.junit.Test; -import org.traccar.ProtocolTest; - -import java.nio.ByteOrder; - -public class Arnavi4ProtocolDecoderTest extends ProtocolTest { - - @Test - public void testHeader1Decode() throws Exception { - - Arnavi4ProtocolDecoder decoder; - - decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); - - verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid HEADER v1 packet with IMEI - "ff22f30c45f5c90f0300")); - - verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid PACKAGE packet with one DATA packet - "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), - position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); - } - - @Test - public void testHeader2Decode() throws Exception { - - Arnavi4ProtocolDecoder decoder; - - decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); - - verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid HEADER v2 packet with IMEI - "ff23f30c45f5c90f0300")); - - verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid PACKAGE packet with two DATA packet - "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), - position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); - } - -} diff --git a/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java new file mode 100644 index 000000000..b634f0cdc --- /dev/null +++ b/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java @@ -0,0 +1,50 @@ +package org.traccar.protocol; + +import org.junit.Assert; +import org.junit.Test; +import org.traccar.ProtocolTest; + +import java.nio.ByteOrder; + +public class Arnavi4FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecodeValidPackets() throws Exception { + + Arnavi4FrameDecoder decoder = new Arnavi4FrameDecoder(); + + Assert.assertEquals( // Valid HEADER v1 packet with IMEI + binary(ByteOrder.LITTLE_ENDIAN, "ff22f30c45f5c90f0300"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "ff22f30c45f5c90f0300"))); + + Assert.assertEquals( // Valid PACKAGE with one DATA packet + binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); + + Assert.assertEquals( // Valid PACKAGE with two DATA packet + binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); + + Assert.assertEquals( // Valid PACKAGE with one TEXT packet. + binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b5d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b5d"))); + + Assert.assertEquals( // Valid PACKAGE with two TEXT packet. + binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"))); + + Assert.assertEquals( // Valid PACKAGE with one BINARY packet. + binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); + + Assert.assertEquals( // Valid PACKAGE with two BINARY packet. + binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); + + Assert.assertEquals( // Valid PACKAGE with answer to server on file transfer + binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"))); + + } + +} \ No newline at end of file diff --git a/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java new file mode 100644 index 000000000..d789b1c9c --- /dev/null +++ b/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java @@ -0,0 +1,40 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import java.nio.ByteOrder; + +public class Arnavi4ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testHeader1Decode() throws Exception { + + Arnavi4ProtocolDecoder decoder; + + decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); + + verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid HEADER v1 packet with IMEI + "ff22f30c45f5c90f0300")); + + verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid PACKAGE packet with one DATA packet + "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); + } + + @Test + public void testHeader2Decode() throws Exception { + + Arnavi4ProtocolDecoder decoder; + + decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); + + verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid HEADER v2 packet with IMEI + "ff23f30c45f5c90f0300")); + + verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid PACKAGE packet with two DATA packet + "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); + } + +} -- cgit v1.2.3 From ee1dbcf048a922b6023b0714989b454b7dfe9587 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 2 Feb 2020 15:36:54 -0800 Subject: Fix merge issues --- src/main/java/org/traccar/helper/Checksum.java | 8 +++ .../org/traccar/protocol/Arnavi4FrameDecoder.java | 21 ++++---- .../java/org/traccar/protocol/Arnavi4Protocol.java | 22 +++------ .../traccar/protocol/Arnavi4ProtocolDecoder.java | 57 ++++++++++------------ src/test/java/org/traccar/helper/ChecksumTest.java | 10 ++++ .../traccar/protocol/Arnavi4FrameDecoderTest.java | 4 +- .../protocol/Arnavi4ProtocolDecoderTest.java | 4 +- 7 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/main/java/org/traccar/helper/Checksum.java b/src/main/java/org/traccar/helper/Checksum.java index adfa697c5..d41dc2992 100644 --- a/src/main/java/org/traccar/helper/Checksum.java +++ b/src/main/java/org/traccar/helper/Checksum.java @@ -168,6 +168,14 @@ public final class Checksum { return checksum; } + public static int modulo256(ByteBuffer buf) { + int checksum = 0; + while (buf.hasRemaining()) { + checksum = (checksum + buf.get()) & 0xFF; + } + return checksum; + } + public static String sum(String msg) { byte checksum = 0; for (byte b : msg.getBytes(StandardCharsets.US_ASCII)) { diff --git a/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java index b13f3fd7d..fae2d3fde 100644 --- a/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java +++ b/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java @@ -15,12 +15,12 @@ */ package org.traccar.protocol; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.handler.codec.frame.FrameDecoder; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; -public class Arnavi4FrameDecoder extends FrameDecoder { +public class Arnavi4FrameDecoder extends BaseFrameDecoder { private static final int MIN_LENGTH = 4; private static final int HEADER_LENGTH = 10; @@ -32,8 +32,7 @@ public class Arnavi4FrameDecoder extends FrameDecoder { private boolean firstPacket = true; @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception { + protected Object decode(ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { if (buf.readableBytes() < MIN_LENGTH) { return null; @@ -44,19 +43,19 @@ public class Arnavi4FrameDecoder extends FrameDecoder { firstPacket = false; length = HEADER_LENGTH; } else { - int index = buf.getUnsignedByte(1); // parcel number + int index = buf.getUnsignedByte(1); if (index == COMMAND_ANSWER_PARCEL_NUMBER) { length = COMMAND_ANSWER_PACKET_LENGTH; } else { - int pos = 2; // start sign + parcel number + int pos = 2; while (pos + PACKET_WRAPPER_LENGTH < buf.readableBytes() && buf.getByte(pos) != PACKAGE_END_SIGN) { int dataLength = buf.getUnsignedShort(pos + 1); - pos += PACKET_WRAPPER_LENGTH + dataLength; // packet type + data length + unixtime + data + crc + pos += PACKET_WRAPPER_LENGTH + dataLength; } - if (buf.getByte(pos) != PACKAGE_END_SIGN) { // end sign + if (buf.getByte(pos) != PACKAGE_END_SIGN) { return null; } diff --git a/src/main/java/org/traccar/protocol/Arnavi4Protocol.java b/src/main/java/org/traccar/protocol/Arnavi4Protocol.java index 381a9b457..8a9337b56 100644 --- a/src/main/java/org/traccar/protocol/Arnavi4Protocol.java +++ b/src/main/java/org/traccar/protocol/Arnavi4Protocol.java @@ -1,4 +1,5 @@ /* + * Copyright 2020 Anton Tananaev (anton@traccar.org) * Copyright 2017 Ivan Muratov (binakot@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,31 +16,20 @@ */ package org.traccar.protocol; -import org.jboss.netty.bootstrap.ServerBootstrap; -import org.jboss.netty.channel.ChannelPipeline; import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; -import java.nio.ByteOrder; -import java.util.List; - public class Arnavi4Protocol extends BaseProtocol { public Arnavi4Protocol() { - super("arnavi4"); - } - - @Override - public void initTrackerServers(List serverList) { - TrackerServer server = new TrackerServer(new ServerBootstrap(), getName()) { + TrackerServer server = new TrackerServer(false, getName()) { @Override - protected void addSpecificHandlers(ChannelPipeline pipeline) { - pipeline.addLast("frameDecoder", new Arnavi4FrameDecoder()); - pipeline.addLast("objectDecoder", new Arnavi4ProtocolDecoder(Arnavi4Protocol.this)); + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new Arnavi4FrameDecoder()); + pipeline.addLast(new Arnavi4ProtocolDecoder(Arnavi4Protocol.this)); } }; - server.setEndianness(ByteOrder.LITTLE_ENDIAN); - serverList.add(server); } } diff --git a/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java index 06abb563f..94ad8bb1f 100644 --- a/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -15,17 +15,17 @@ */ package org.traccar.protocol; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.channel.Channel; +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.helper.Checksum; import org.traccar.model.Position; import java.net.SocketAddress; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.util.Date; import java.util.LinkedList; import java.util.List; @@ -52,30 +52,24 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { private void sendResponse(Channel channel, byte version, int index) { if (channel != null) { - final ChannelBuffer response; + ByteBuf response = Unpooled.buffer(); + response.writeByte(0x7b); if (version == HEADER_VERSION_1) { - response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 4); - response.writeByte(0x7b); response.writeByte(0x00); response.writeByte((byte) index); - response.writeByte(0x7d); } else if (version == HEADER_VERSION_2) { - response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 9); - response.writeByte(0x7b); response.writeByte(0x04); response.writeByte(0x00); - byte[] timeBytes = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)).array(); - response.writeByte(Checksum.modulo256(timeBytes)); - response.writeBytes(timeBytes); - response.writeByte(0x7d); - } else { - return; // Ignore unsupported header's versions + ByteBuffer time = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)); + response.writeByte(Checksum.modulo256(time)); + response.writeBytes(time); } - channel.write(response); + response.writeByte(0x7d); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); } } - private Position decodePosition(DeviceSession deviceSession, ChannelBuffer buf, int length, Date time) { + private Position decodePosition(DeviceSession deviceSession, ByteBuf buf, int length, Date time) { final Position position = new Position(); position.setProtocol(getProtocolName()); @@ -88,12 +82,12 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { short tag = buf.readUnsignedByte(); switch (tag) { case TAG_LATITUDE: - position.setLatitude(buf.readFloat()); + position.setLatitude(buf.readFloatLE()); position.setValid(true); break; case TAG_LONGITUDE: - position.setLongitude(buf.readFloat()); + position.setLongitude(buf.readFloatLE()); position.setValid(true); break; @@ -101,26 +95,25 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { position.setCourse(buf.readUnsignedByte() * 2); position.setAltitude(buf.readUnsignedByte() * 10); byte satellites = buf.readByte(); - position.set(Position.KEY_SATELLITES, satellites & 0x0F + (satellites >> 4) & 0x0F); // gps+glonass + position.set(Position.KEY_SATELLITES, satellites & 0x0F + (satellites >> 4) & 0x0F); position.setSpeed(buf.readUnsignedByte()); break; default: - buf.readBytes(4); // Skip unsupported tags + buf.skipBytes(4); break; } - readBytes += 5; // 1 byte tag + 4 bytes value + readBytes += 1 + 4; } return position; } @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - ChannelBuffer buf = (ChannelBuffer) msg; + ByteBuf buf = (ByteBuf) msg; byte startSign = buf.readByte(); @@ -128,7 +121,7 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { byte version = buf.readByte(); - String imei = String.valueOf(buf.readLong()); + String imei = String.valueOf(buf.readLongLE()); DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); if (deviceSession != null) { @@ -155,20 +148,20 @@ public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { case RECORD_TEXT: case RECORD_FILE: case RECORD_BINARY: - int length = buf.readUnsignedShort(); - Date time = new Date(buf.readUnsignedInt() * 1000); + int length = buf.readUnsignedShortLE(); + Date time = new Date(buf.readUnsignedIntLE() * 1000); if (recordType == RECORD_DATA) { positions.add(decodePosition(deviceSession, buf, length, time)); } else { - buf.readBytes(length); // Skip other types of record + buf.readBytes(length); } - buf.readUnsignedByte(); // crc + buf.readUnsignedByte(); // checksum break; default: - return null; // Ignore unsupported types of record + return null; } recordType = buf.readByte(); diff --git a/src/test/java/org/traccar/helper/ChecksumTest.java b/src/test/java/org/traccar/helper/ChecksumTest.java index 5737b9ff5..ff48527bc 100644 --- a/src/test/java/org/traccar/helper/ChecksumTest.java +++ b/src/test/java/org/traccar/helper/ChecksumTest.java @@ -4,6 +4,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.junit.Test; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import static org.junit.Assert.assertEquals; @@ -36,4 +37,13 @@ public class ChecksumTest { assertEquals(0, Checksum.luhn(63070019470771L)); } + @Test + public void testModulo256() { + assertEquals(0x00, Checksum.modulo256(ByteBuffer.wrap(new byte[] {0x00}))); + assertEquals(0x00, Checksum.modulo256(ByteBuffer.wrap(new byte[] {0x00, 0x00, 0x00}))); + assertEquals(0xca, Checksum.modulo256(ByteBuffer.wrap(new byte[] {0x77, 0x77, 0x77, 0x77, 0x77, 0x77}))); + + + } + } diff --git a/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java index b634f0cdc..ef14b3427 100644 --- a/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java @@ -8,7 +8,7 @@ import java.nio.ByteOrder; public class Arnavi4FrameDecoderTest extends ProtocolTest { - @Test + /*@Test public void testDecodeValidPackets() throws Exception { Arnavi4FrameDecoder decoder = new Arnavi4FrameDecoder(); @@ -45,6 +45,6 @@ public class Arnavi4FrameDecoderTest extends ProtocolTest { binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"), decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"))); - } + }*/ } \ No newline at end of file diff --git a/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java index d789b1c9c..191d69a42 100644 --- a/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java @@ -7,7 +7,7 @@ import java.nio.ByteOrder; public class Arnavi4ProtocolDecoderTest extends ProtocolTest { - @Test + /*@Test public void testHeader1Decode() throws Exception { Arnavi4ProtocolDecoder decoder; @@ -35,6 +35,6 @@ public class Arnavi4ProtocolDecoderTest extends ProtocolTest { verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid PACKAGE packet with two DATA packet "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); - } + }*/ } -- cgit v1.2.3 From c6ce16f71d3cb8c04c080ebd57c5dd53e2b9229a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 2 Feb 2020 15:55:32 -0800 Subject: Fix unit tests --- .../org/traccar/protocol/Arnavi4FrameDecoder.java | 2 +- .../traccar/protocol/Arnavi4FrameDecoderTest.java | 57 ++++++++++------------ .../protocol/Arnavi4ProtocolDecoderTest.java | 14 +++--- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java index fae2d3fde..6a6f820b0 100644 --- a/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java +++ b/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java @@ -51,7 +51,7 @@ public class Arnavi4FrameDecoder extends BaseFrameDecoder { while (pos + PACKET_WRAPPER_LENGTH < buf.readableBytes() && buf.getByte(pos) != PACKAGE_END_SIGN) { - int dataLength = buf.getUnsignedShort(pos + 1); + int dataLength = buf.getUnsignedShortLE(pos + 1); pos += PACKET_WRAPPER_LENGTH + dataLength; } diff --git a/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java index ef14b3427..aa3f85820 100644 --- a/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java @@ -1,50 +1,47 @@ package org.traccar.protocol; -import org.junit.Assert; import org.junit.Test; import org.traccar.ProtocolTest; -import java.nio.ByteOrder; - public class Arnavi4FrameDecoderTest extends ProtocolTest { - /*@Test + @Test public void testDecodeValidPackets() throws Exception { Arnavi4FrameDecoder decoder = new Arnavi4FrameDecoder(); - Assert.assertEquals( // Valid HEADER v1 packet with IMEI - binary(ByteOrder.LITTLE_ENDIAN, "ff22f30c45f5c90f0300"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "ff22f30c45f5c90f0300"))); + verifyFrame( + binary("ff22f30c45f5c90f0300"), + decoder.decode(null, null, binary("ff22f30c45f5c90f0300"))); - Assert.assertEquals( // Valid PACKAGE with one DATA packet - binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); + verifyFrame( + binary("5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + decoder.decode(null, null, binary("5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); - Assert.assertEquals( // Valid PACKAGE with two DATA packet - binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); + verifyFrame( + binary("5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + decoder.decode(null, null, binary("5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); - Assert.assertEquals( // Valid PACKAGE with one TEXT packet. - binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b5d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b5d"))); + verifyFrame( + binary("5b01030700e3f16b50747261636361721b5d"), + decoder.decode(null, null, binary("5b01030700e3f16b50747261636361721b5d"))); - Assert.assertEquals( // Valid PACKAGE with two TEXT packet. - binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"))); + verifyFrame( + binary("5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"), + decoder.decode(null, null, binary("5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"))); - Assert.assertEquals( // Valid PACKAGE with one BINARY packet. - binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); + verifyFrame( + binary("5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), + decoder.decode(null, null, binary("5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); - Assert.assertEquals( // Valid PACKAGE with two BINARY packet. - binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); + verifyFrame( + binary("5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), + decoder.decode(null, null, binary("5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); - Assert.assertEquals( // Valid PACKAGE with answer to server on file transfer - binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"), - decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "5bfd005d"))); + verifyFrame( + binary("5bfd005d"), + decoder.decode(null, null, binary("5bfd005d"))); - }*/ + } -} \ No newline at end of file +} diff --git a/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java index 191d69a42..2628188b9 100644 --- a/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java @@ -3,21 +3,19 @@ package org.traccar.protocol; import org.junit.Test; import org.traccar.ProtocolTest; -import java.nio.ByteOrder; - public class Arnavi4ProtocolDecoderTest extends ProtocolTest { - /*@Test + @Test public void testHeader1Decode() throws Exception { Arnavi4ProtocolDecoder decoder; decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); - verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid HEADER v1 packet with IMEI + verifyNull(decoder, binary( "ff22f30c45f5c90f0300")); - verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid PACKAGE packet with one DATA packet + verifyPositions(decoder, binary( "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); } @@ -29,12 +27,12 @@ public class Arnavi4ProtocolDecoderTest extends ProtocolTest { decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); - verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid HEADER v2 packet with IMEI + verifyNull(decoder, binary( "ff23f30c45f5c90f0300")); - verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, // Valid PACKAGE packet with two DATA packet + verifyPositions(decoder, binary( "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); - }*/ + } } -- cgit v1.2.3 From 00f8b1ff552f49ebcb5c1d13c85bd84911a2ac8d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 2 Feb 2020 16:06:09 -0800 Subject: Refactor frame decoder --- .../org/traccar/protocol/Arnavi4FrameDecoder.java | 28 +++++++++------------- .../traccar/protocol/Arnavi4ProtocolDecoder.java | 1 + 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java index 6a6f820b0..8a2681b55 100644 --- a/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java +++ b/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java @@ -1,4 +1,5 @@ /* + * Copyright 2020 Anton Tananaev (anton@traccar.org) * Copyright 2017 Ivan Muratov (binakot@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,11 +23,9 @@ import org.traccar.BaseFrameDecoder; public class Arnavi4FrameDecoder extends BaseFrameDecoder { - private static final int MIN_LENGTH = 4; private static final int HEADER_LENGTH = 10; private static final int PACKET_WRAPPER_LENGTH = 8; - private static final int COMMAND_ANSWER_PACKET_LENGTH = 4; - private static final int COMMAND_ANSWER_PARCEL_NUMBER = 0xfd; + private static final int RESULT_TYPE = 0xfd; private static final byte PACKAGE_END_SIGN = 0x5d; private boolean firstPacket = true; @@ -34,7 +33,7 @@ public class Arnavi4FrameDecoder extends BaseFrameDecoder { @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - if (buf.readableBytes() < MIN_LENGTH) { + if (buf.readableBytes() < 4) { return null; } @@ -43,23 +42,18 @@ public class Arnavi4FrameDecoder extends BaseFrameDecoder { firstPacket = false; length = HEADER_LENGTH; } else { - int index = buf.getUnsignedByte(1); - if (index == COMMAND_ANSWER_PARCEL_NUMBER) { - length = COMMAND_ANSWER_PACKET_LENGTH; + int type = buf.getUnsignedByte(1); + if (type == RESULT_TYPE) { + length = 4; } else { - int pos = 2; - while (pos + PACKET_WRAPPER_LENGTH < buf.readableBytes() - && buf.getByte(pos) != PACKAGE_END_SIGN) { - - int dataLength = buf.getUnsignedShortLE(pos + 1); - pos += PACKET_WRAPPER_LENGTH + dataLength; + int index = 2; + while (index + PACKET_WRAPPER_LENGTH < buf.readableBytes() && buf.getByte(index) != PACKAGE_END_SIGN) { + index += PACKET_WRAPPER_LENGTH + buf.getUnsignedShortLE(index + 1); } - - if (buf.getByte(pos) != PACKAGE_END_SIGN) { + if (buf.getByte(index) != PACKAGE_END_SIGN) { return null; } - - length = pos + 1; + length = index + 1; } } diff --git a/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java index 94ad8bb1f..3e0fa5d9f 100644 --- a/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java @@ -1,4 +1,5 @@ /* + * Copyright 2020 Anton Tananaev (anton@traccar.org) * Copyright 2017 Ivan Muratov (binakot@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); -- cgit v1.2.3 From 71735f0c9b17ad1c64a4335a196b4c765b4499c1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 2 Feb 2020 16:26:46 -0800 Subject: Rename classes --- .../org/traccar/protocol/Arnavi4FrameDecoder.java | 67 -------- .../java/org/traccar/protocol/Arnavi4Protocol.java | 35 ---- .../traccar/protocol/Arnavi4ProtocolDecoder.java | 176 -------------------- .../protocol/ArnaviBinaryProtocolDecoder.java | 177 +++++++++++++++++++++ .../org/traccar/protocol/ArnaviFrameDecoder.java | 81 ++++++++++ .../java/org/traccar/protocol/ArnaviProtocol.java | 2 +- .../traccar/protocol/ArnaviProtocolDecoder.java | 105 ------------ .../protocol/ArnaviTextProtocolDecoder.java | 105 ++++++++++++ .../traccar/protocol/Arnavi4FrameDecoderTest.java | 47 ------ .../protocol/Arnavi4ProtocolDecoderTest.java | 38 ----- .../protocol/ArnaviBinaryProtocolDecoderTest.java | 38 +++++ .../traccar/protocol/ArnaviFrameDecoderTest.java | 51 ++++++ .../protocol/ArnaviProtocolDecoderTest.java | 42 ----- .../protocol/ArnaviTextProtocolDecoderTest.java | 42 +++++ 14 files changed, 495 insertions(+), 511 deletions(-) delete mode 100644 src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java delete mode 100644 src/main/java/org/traccar/protocol/Arnavi4Protocol.java delete mode 100644 src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/ArnaviFrameDecoder.java delete mode 100644 src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java delete mode 100644 src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java delete mode 100644 src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java delete mode 100644 src/test/java/org/traccar/protocol/ArnaviProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java diff --git a/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java b/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java deleted file mode 100644 index 8a2681b55..000000000 --- a/src/main/java/org/traccar/protocol/Arnavi4FrameDecoder.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2020 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Ivan Muratov (binakot@gmail.com) - * - * 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.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class Arnavi4FrameDecoder extends BaseFrameDecoder { - - private static final int HEADER_LENGTH = 10; - private static final int PACKET_WRAPPER_LENGTH = 8; - private static final int RESULT_TYPE = 0xfd; - private static final byte PACKAGE_END_SIGN = 0x5d; - - private boolean firstPacket = true; - - @Override - protected Object decode(ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 4) { - return null; - } - - int length; - if (firstPacket) { - firstPacket = false; - length = HEADER_LENGTH; - } else { - int type = buf.getUnsignedByte(1); - if (type == RESULT_TYPE) { - length = 4; - } else { - int index = 2; - while (index + PACKET_WRAPPER_LENGTH < buf.readableBytes() && buf.getByte(index) != PACKAGE_END_SIGN) { - index += PACKET_WRAPPER_LENGTH + buf.getUnsignedShortLE(index + 1); - } - if (buf.getByte(index) != PACKAGE_END_SIGN) { - return null; - } - length = index + 1; - } - } - - if (buf.readableBytes() >= length) { - return buf.readBytes(length); - } - - return null; - } - -} diff --git a/src/main/java/org/traccar/protocol/Arnavi4Protocol.java b/src/main/java/org/traccar/protocol/Arnavi4Protocol.java deleted file mode 100644 index 8a9337b56..000000000 --- a/src/main/java/org/traccar/protocol/Arnavi4Protocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2020 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Ivan Muratov (binakot@gmail.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.traccar.protocol; - -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Arnavi4Protocol extends BaseProtocol { - - public Arnavi4Protocol() { - TrackerServer server = new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new Arnavi4FrameDecoder()); - pipeline.addLast(new Arnavi4ProtocolDecoder(Arnavi4Protocol.this)); - } - }; - } - -} diff --git a/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java deleted file mode 100644 index 3e0fa5d9f..000000000 --- a/src/main/java/org/traccar/protocol/Arnavi4ProtocolDecoder.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2020 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Ivan Muratov (binakot@gmail.com) - * - * 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.helper.Checksum; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class Arnavi4ProtocolDecoder extends BaseProtocolDecoder { - - private static final byte HEADER_START_SIGN = (byte) 0xff; - private static final byte HEADER_VERSION_1 = 0x22; - private static final byte HEADER_VERSION_2 = 0x23; - - private static final byte RECORD_PING = 0x00; - private static final byte RECORD_DATA = 0x01; - private static final byte RECORD_TEXT = 0x03; - private static final byte RECORD_FILE = 0x04; - private static final byte RECORD_BINARY = 0x06; - - private static final byte TAG_LATITUDE = 3; - private static final byte TAG_LONGITUDE = 4; - private static final byte TAG_COORD_PARAMS = 5; - - public Arnavi4ProtocolDecoder(Arnavi4Protocol protocol) { - super(protocol); - } - - private void sendResponse(Channel channel, byte version, int index) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeByte(0x7b); - if (version == HEADER_VERSION_1) { - response.writeByte(0x00); - response.writeByte((byte) index); - } else if (version == HEADER_VERSION_2) { - response.writeByte(0x04); - response.writeByte(0x00); - ByteBuffer time = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)); - response.writeByte(Checksum.modulo256(time)); - response.writeBytes(time); - } - response.writeByte(0x7d); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - private Position decodePosition(DeviceSession deviceSession, ByteBuf buf, int length, Date time) { - - final Position position = new Position(); - position.setProtocol(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(time); - - int readBytes = 0; - while (readBytes < length) { - short tag = buf.readUnsignedByte(); - switch (tag) { - case TAG_LATITUDE: - position.setLatitude(buf.readFloatLE()); - position.setValid(true); - break; - - case TAG_LONGITUDE: - position.setLongitude(buf.readFloatLE()); - position.setValid(true); - break; - - case TAG_COORD_PARAMS: - position.setCourse(buf.readUnsignedByte() * 2); - position.setAltitude(buf.readUnsignedByte() * 10); - byte satellites = buf.readByte(); - position.set(Position.KEY_SATELLITES, satellites & 0x0F + (satellites >> 4) & 0x0F); - position.setSpeed(buf.readUnsignedByte()); - break; - - default: - buf.skipBytes(4); - break; - } - - readBytes += 1 + 4; - } - - return position; - } - - @Override - protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - byte startSign = buf.readByte(); - - if (startSign == HEADER_START_SIGN) { - - byte version = buf.readByte(); - - String imei = String.valueOf(buf.readLongLE()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - - if (deviceSession != null) { - sendResponse(channel, version, 0); - } - - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - int index = buf.readUnsignedByte(); - - byte recordType = buf.readByte(); - while (buf.readableBytes() > 0) { - switch (recordType) { - case RECORD_PING: - case RECORD_DATA: - case RECORD_TEXT: - case RECORD_FILE: - case RECORD_BINARY: - int length = buf.readUnsignedShortLE(); - Date time = new Date(buf.readUnsignedIntLE() * 1000); - - if (recordType == RECORD_DATA) { - positions.add(decodePosition(deviceSession, buf, length, time)); - } else { - buf.readBytes(length); - } - - buf.readUnsignedByte(); // checksum - break; - - default: - return null; - } - - recordType = buf.readByte(); - } - - sendResponse(channel, HEADER_VERSION_1, index); - - return positions; - } - -} diff --git a/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java new file mode 100644 index 000000000..0924cfc40 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java @@ -0,0 +1,177 @@ +/* + * Copyright 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Ivan Muratov (binakot@gmail.com) + * + * 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.Checksum; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class ArnaviBinaryProtocolDecoder extends BaseProtocolDecoder { + + private static final byte HEADER_START_SIGN = (byte) 0xff; + private static final byte HEADER_VERSION_1 = 0x22; + private static final byte HEADER_VERSION_2 = 0x23; + + private static final byte RECORD_PING = 0x00; + private static final byte RECORD_DATA = 0x01; + private static final byte RECORD_TEXT = 0x03; + private static final byte RECORD_FILE = 0x04; + private static final byte RECORD_BINARY = 0x06; + + private static final byte TAG_LATITUDE = 3; + private static final byte TAG_LONGITUDE = 4; + private static final byte TAG_COORD_PARAMS = 5; + + public ArnaviBinaryProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private void sendResponse(Channel channel, byte version, int index) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(0x7b); + if (version == HEADER_VERSION_1) { + response.writeByte(0x00); + response.writeByte((byte) index); + } else if (version == HEADER_VERSION_2) { + response.writeByte(0x04); + response.writeByte(0x00); + ByteBuffer time = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)); + response.writeByte(Checksum.modulo256(time)); + response.writeBytes(time); + } + response.writeByte(0x7d); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + private Position decodePosition(DeviceSession deviceSession, ByteBuf buf, int length, Date time) { + + final Position position = new Position(); + position.setProtocol(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(time); + + int readBytes = 0; + while (readBytes < length) { + short tag = buf.readUnsignedByte(); + switch (tag) { + case TAG_LATITUDE: + position.setLatitude(buf.readFloatLE()); + position.setValid(true); + break; + + case TAG_LONGITUDE: + position.setLongitude(buf.readFloatLE()); + position.setValid(true); + break; + + case TAG_COORD_PARAMS: + position.setCourse(buf.readUnsignedByte() * 2); + position.setAltitude(buf.readUnsignedByte() * 10); + byte satellites = buf.readByte(); + position.set(Position.KEY_SATELLITES, satellites & 0x0F + (satellites >> 4) & 0x0F); + position.setSpeed(buf.readUnsignedByte()); + break; + + default: + buf.skipBytes(4); + break; + } + + readBytes += 1 + 4; + } + + return position; + } + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + byte startSign = buf.readByte(); + + if (startSign == HEADER_START_SIGN) { + + byte version = buf.readByte(); + + String imei = String.valueOf(buf.readLongLE()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + + if (deviceSession != null) { + sendResponse(channel, version, 0); + } + + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + int index = buf.readUnsignedByte(); + + byte recordType = buf.readByte(); + while (buf.readableBytes() > 0) { + switch (recordType) { + case RECORD_PING: + case RECORD_DATA: + case RECORD_TEXT: + case RECORD_FILE: + case RECORD_BINARY: + int length = buf.readUnsignedShortLE(); + Date time = new Date(buf.readUnsignedIntLE() * 1000); + + if (recordType == RECORD_DATA) { + positions.add(decodePosition(deviceSession, buf, length, time)); + } else { + buf.readBytes(length); + } + + buf.readUnsignedByte(); // checksum + break; + + default: + return null; + } + + recordType = buf.readByte(); + } + + sendResponse(channel, HEADER_VERSION_1, index); + + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/ArnaviFrameDecoder.java b/src/main/java/org/traccar/protocol/ArnaviFrameDecoder.java new file mode 100644 index 000000000..3db11113d --- /dev/null +++ b/src/main/java/org/traccar/protocol/ArnaviFrameDecoder.java @@ -0,0 +1,81 @@ +/* + * Copyright 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Ivan Muratov (binakot@gmail.com) + * + * 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.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; +import org.traccar.helper.BufferUtil; + +public class ArnaviFrameDecoder extends BaseFrameDecoder { + + private static final int HEADER_LENGTH = 10; + private static final int PACKET_WRAPPER_LENGTH = 8; + private static final int RESULT_TYPE = 0xfd; + private static final byte PACKAGE_END_SIGN = 0x5d; + + private boolean firstPacket = true; + + @Override + protected Object decode(ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 4) { + return null; + } + + if (buf.getByte(buf.readerIndex()) == '$') { + + int index = BufferUtil.indexOf("\r\n", buf); + if (index > 0) { + ByteBuf frame = buf.readRetainedSlice(index - buf.readerIndex()); + buf.skipBytes(2); + return frame; + } + + } else { + + int length; + if (firstPacket) { + firstPacket = false; + length = HEADER_LENGTH; + } else { + int type = buf.getUnsignedByte(1); + if (type == RESULT_TYPE) { + length = 4; + } else { + int index = 2; + while (index + PACKET_WRAPPER_LENGTH < buf.readableBytes() && buf.getByte(index) != PACKAGE_END_SIGN) { + index += PACKET_WRAPPER_LENGTH + buf.getUnsignedShortLE(index + 1); + } + if (buf.getByte(index) != PACKAGE_END_SIGN) { + return null; + } + length = index + 1; + } + } + + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/ArnaviProtocol.java b/src/main/java/org/traccar/protocol/ArnaviProtocol.java index afe491865..11101097b 100644 --- a/src/main/java/org/traccar/protocol/ArnaviProtocol.java +++ b/src/main/java/org/traccar/protocol/ArnaviProtocol.java @@ -31,7 +31,7 @@ public class ArnaviProtocol extends BaseProtocol { pipeline.addLast(new LineBasedFrameDecoder(1024)); pipeline.addLast(new StringDecoder()); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new ArnaviProtocolDecoder(ArnaviProtocol.this)); + pipeline.addLast(new ArnaviTextProtocolDecoder(ArnaviProtocol.this)); } }); } diff --git a/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java deleted file mode 100644 index 7996cf429..000000000 --- a/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2015 - 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.Protocol; -import org.traccar.helper.DateBuilder; -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 ArnaviProtocolDecoder extends BaseProtocolDecoder { - - public ArnaviProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$AV,") - .number("Vd,") // type - .number("(d+),") // device id - .number("(d+),") // index - .number("(d+),") // power - .number("(d+),") // battery - .number("-?d+,") - .expression("[01],") // movement - .expression("([01]),") // ignition - .number("(d+),") // input - .number("d+,d+,") // input 1 - .number("d+,d+,").optional() // input 2 - .expression("[01],") // fix type - .number("(d+),") // satellites - .groupBegin() - .number("(d+.d+)?,") // altitude - .number("(?:d+.d+)?,") // geoid height - .groupEnd("?") - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(dd)(dd.d+)([NS]),") // latitude - .number("(ddd)(dd.d+)([EW]),") // longitude - .number("(d+.d+),") // speed - .number("(d+.d+),") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_INDEX, parser.nextInt()); - position.set(Position.KEY_POWER, parser.nextInt() * 0.01); - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.01); - position.set(Position.KEY_IGNITION, parser.nextInt() == 1); - position.set(Position.KEY_INPUT, parser.nextInt()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - - position.setAltitude(parser.nextDouble(0)); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); - - position.setValid(true); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble()); - position.setCourse(parser.nextDouble()); - - dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setTime(dateBuilder.getDate()); - - return position; - } - -} diff --git a/src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java new file mode 100644 index 000000000..8c4f743bc --- /dev/null +++ b/src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java @@ -0,0 +1,105 @@ +/* + * Copyright 2015 - 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.Protocol; +import org.traccar.helper.DateBuilder; +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 ArnaviTextProtocolDecoder extends BaseProtocolDecoder { + + public ArnaviTextProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$AV,") + .number("Vd,") // type + .number("(d+),") // device id + .number("(d+),") // index + .number("(d+),") // power + .number("(d+),") // battery + .number("-?d+,") + .expression("[01],") // movement + .expression("([01]),") // ignition + .number("(d+),") // input + .number("d+,d+,") // input 1 + .number("d+,d+,").optional() // input 2 + .expression("[01],") // fix type + .number("(d+),") // satellites + .groupBegin() + .number("(d+.d+)?,") // altitude + .number("(?:d+.d+)?,") // geoid height + .groupEnd("?") + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(dd)(dd.d+)([NS]),") // latitude + .number("(ddd)(dd.d+)([EW]),") // longitude + .number("(d+.d+),") // speed + .number("(d+.d+),") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_INDEX, parser.nextInt()); + position.set(Position.KEY_POWER, parser.nextInt() * 0.01); + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.01); + position.set(Position.KEY_IGNITION, parser.nextInt() == 1); + position.set(Position.KEY_INPUT, parser.nextInt()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + + position.setAltitude(parser.nextDouble(0)); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(true); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextDouble()); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + return position; + } + +} diff --git a/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java deleted file mode 100644 index aa3f85820..000000000 --- a/src/test/java/org/traccar/protocol/Arnavi4FrameDecoderTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.traccar.protocol; - -import org.junit.Test; -import org.traccar.ProtocolTest; - -public class Arnavi4FrameDecoderTest extends ProtocolTest { - - @Test - public void testDecodeValidPackets() throws Exception { - - Arnavi4FrameDecoder decoder = new Arnavi4FrameDecoder(); - - verifyFrame( - binary("ff22f30c45f5c90f0300"), - decoder.decode(null, null, binary("ff22f30c45f5c90f0300"))); - - verifyFrame( - binary("5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), - decoder.decode(null, null, binary("5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); - - verifyFrame( - binary("5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), - decoder.decode(null, null, binary("5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); - - verifyFrame( - binary("5b01030700e3f16b50747261636361721b5d"), - decoder.decode(null, null, binary("5b01030700e3f16b50747261636361721b5d"))); - - verifyFrame( - binary("5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"), - decoder.decode(null, null, binary("5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"))); - - verifyFrame( - binary("5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), - decoder.decode(null, null, binary("5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); - - verifyFrame( - binary("5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), - decoder.decode(null, null, binary("5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); - - verifyFrame( - binary("5bfd005d"), - decoder.decode(null, null, binary("5bfd005d"))); - - } - -} diff --git a/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java deleted file mode 100644 index 2628188b9..000000000 --- a/src/test/java/org/traccar/protocol/Arnavi4ProtocolDecoderTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.traccar.protocol; - -import org.junit.Test; -import org.traccar.ProtocolTest; - -public class Arnavi4ProtocolDecoderTest extends ProtocolTest { - - @Test - public void testHeader1Decode() throws Exception { - - Arnavi4ProtocolDecoder decoder; - - decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); - - verifyNull(decoder, binary( - "ff22f30c45f5c90f0300")); - - verifyPositions(decoder, binary( - "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), - position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); - } - - @Test - public void testHeader2Decode() throws Exception { - - Arnavi4ProtocolDecoder decoder; - - decoder = new Arnavi4ProtocolDecoder(new Arnavi4Protocol()); - - verifyNull(decoder, binary( - "ff23f30c45f5c90f0300")); - - verifyPositions(decoder, binary( - "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), - position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); - } - -} diff --git a/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java new file mode 100644 index 000000000..f2940de59 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java @@ -0,0 +1,38 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ArnaviBinaryProtocolDecoderTest extends ProtocolTest { + + @Test + public void testHeader1Decode() throws Exception { + + ArnaviBinaryProtocolDecoder decoder; + + decoder = new ArnaviBinaryProtocolDecoder(null); + + verifyNull(decoder, binary( + "ff22f30c45f5c90f0300")); + + verifyPositions(decoder, binary( + "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); + } + + @Test + public void testHeader2Decode() throws Exception { + + ArnaviBinaryProtocolDecoder decoder; + + decoder = new ArnaviBinaryProtocolDecoder(null); + + verifyNull(decoder, binary( + "ff23f30c45f5c90f0300")); + + verifyPositions(decoder, binary( + "5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + position("2017-07-07 05:09:55.000", true, 45.05597, 39.03347)); + } + +} diff --git a/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java new file mode 100644 index 000000000..90eb20296 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java @@ -0,0 +1,51 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ArnaviFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecodeValidPackets() throws Exception { + + ArnaviFrameDecoder decoder = new ArnaviFrameDecoder(); + + verifyFrame( + binary("2441562c563344492c38353136342c3231342c2d312c31392c30303030344634462c30303030303935452c30433030303030322c3836333037313031333034313631382c38393939373031353630333832353236363232462c2a3039"), + decoder.decode(null, null, binary("2441562c563344492c38353136342c3231342c2d312c31392c30303030344634462c30303030303935452c30433030303030322c3836333037313031333034313631382c38393939373031353630333832353236363232462c2a30390d0a"))); + + verifyFrame( + binary("ff22f30c45f5c90f0300"), + decoder.decode(null, null, binary("ff22f30c45f5c90f0300"))); + + verifyFrame( + binary("5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + decoder.decode(null, null, binary("5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); + + verifyFrame( + binary("5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"), + decoder.decode(null, null, binary("5b01012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa3701000029012800a3175f5903513934420447221c42055402781E0900f0c5215b4e0084005c00007c005d0000a300fa37010000295d"))); + + verifyFrame( + binary("5b01030700e3f16b50747261636361721b5d"), + decoder.decode(null, null, binary("5b01030700e3f16b50747261636361721b5d"))); + + verifyFrame( + binary("5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"), + decoder.decode(null, null, binary("5b01030700e3f16b50747261636361721b030700e3f16b50747261636361721b5d"))); + + verifyFrame( + binary("5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), + decoder.decode(null, null, binary("5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); + + verifyFrame( + binary("5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"), + decoder.decode(null, null, binary("5b01061400e3f16b5003298b5e4204cbd514420500191000080400ff021b061400e3f16b5003298b5e4204cbd514420500191000080400ff021b5d"))); + + verifyFrame( + binary("5bfd005d"), + decoder.decode(null, null, binary("5bfd005d"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/ArnaviProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviProtocolDecoderTest.java deleted file mode 100644 index 6b075facc..000000000 --- a/src/test/java/org/traccar/protocol/ArnaviProtocolDecoderTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.traccar.protocol; - -import org.junit.Test; -import org.traccar.ProtocolTest; - -public class ArnaviProtocolDecoderTest extends ProtocolTest { - - @Test - public void testDecode() throws Exception { - - ArnaviProtocolDecoder decoder = new ArnaviProtocolDecoder(null); - - verifyPosition(decoder, text( - "$AV,V4,999999,12487,2277,203,65534,0,0,193,65535,65535,65535,65535,1,13,80.0,56.1,200741,5950.6773N,03029.1043E,300.0,360.0,121012,65535,65535,65535,SF*6E")); - - verifyNull(decoder, text( - "$AV,V3DI,85164,20707,-1,19,0008C56A,000879AC,0C000002,863071013041618,89997077111301204297,*0B")); - - verifyNull(decoder, text( - "$AV,V6SD,85164,20708,-1,3,6,37,33,*52")); - - verifyAttributes(decoder, text( - "$AV,V4,85164,20709,1148,418,-1,0,1,192,0,0,0,0,0,0,,,000023,0000.0000N,00000.0000E,0.0,0.0,060180,0,0,32767,*4F")); - - verifyNull(decoder, text( - "$AV,V3GSMINFO,85164,-1,20450,KMOBILE,1,2,1,23,0,40101,cc3,1,ce19,401,16,65304,5613,72,,SF*7F")); - - verifyAttributes(decoder, text( - "$AV,V4,85164,20451,1146,418,-1,1,1,192,0,0,0,0,0,0,,,104340,0000.0000N,00000.0000E,0.0,0.0,060219,11,0,32767,,SF*47")); - - verifyNull(decoder, text( - "$AV,V6SD,85164,20452,-1,3,3,5,6769,,SF*5D")); - - verifyPosition(decoder, text( - "$AV,V2,32768,12487,2277,203,-1,0,0,193,0,0,1,13,200741,5950.6773N,03029.1043E,0.0,0.0,121012,*6E")); - - verifyPosition(decoder, text( - "$AV,V3,999999,12487,2277,203,65534,0,0,193,65535,65535,65535,65535,1,13,200741,5950.6773N,03029.1043E,300.0,360.0,121012,65535,65535,65535,SF*6E")); - - } - -} diff --git a/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java new file mode 100644 index 000000000..065a28580 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java @@ -0,0 +1,42 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ArnaviTextProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ArnaviTextProtocolDecoder decoder = new ArnaviTextProtocolDecoder(null); + + verifyPosition(decoder, text( + "$AV,V4,999999,12487,2277,203,65534,0,0,193,65535,65535,65535,65535,1,13,80.0,56.1,200741,5950.6773N,03029.1043E,300.0,360.0,121012,65535,65535,65535,SF*6E")); + + verifyNull(decoder, text( + "$AV,V3DI,85164,20707,-1,19,0008C56A,000879AC,0C000002,863071013041618,89997077111301204297,*0B")); + + verifyNull(decoder, text( + "$AV,V6SD,85164,20708,-1,3,6,37,33,*52")); + + verifyAttributes(decoder, text( + "$AV,V4,85164,20709,1148,418,-1,0,1,192,0,0,0,0,0,0,,,000023,0000.0000N,00000.0000E,0.0,0.0,060180,0,0,32767,*4F")); + + verifyNull(decoder, text( + "$AV,V3GSMINFO,85164,-1,20450,KMOBILE,1,2,1,23,0,40101,cc3,1,ce19,401,16,65304,5613,72,,SF*7F")); + + verifyAttributes(decoder, text( + "$AV,V4,85164,20451,1146,418,-1,1,1,192,0,0,0,0,0,0,,,104340,0000.0000N,00000.0000E,0.0,0.0,060219,11,0,32767,,SF*47")); + + verifyNull(decoder, text( + "$AV,V6SD,85164,20452,-1,3,3,5,6769,,SF*5D")); + + verifyPosition(decoder, text( + "$AV,V2,32768,12487,2277,203,-1,0,0,193,0,0,1,13,200741,5950.6773N,03029.1043E,0.0,0.0,121012,*6E")); + + verifyPosition(decoder, text( + "$AV,V3,999999,12487,2277,203,65534,0,0,193,65535,65535,65535,65535,1,13,200741,5950.6773N,03029.1043E,300.0,360.0,121012,65535,65535,65535,SF*6E")); + + } + +} -- cgit v1.2.3 From 8b48d8b52f9c29a892dfe4381b3a7226226a76eb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 2 Feb 2020 16:31:10 -0800 Subject: Switch between binary and text --- .../java/org/traccar/protocol/ArnaviProtocol.java | 11 ++--- .../traccar/protocol/ArnaviProtocolDecoder.java | 49 ++++++++++++++++++++++ .../protocol/ArnaviTextProtocolDecoder.java | 7 +++- .../protocol/ArnaviTextProtocolDecoderTest.java | 18 ++++---- 4 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java diff --git a/src/main/java/org/traccar/protocol/ArnaviProtocol.java b/src/main/java/org/traccar/protocol/ArnaviProtocol.java index 11101097b..aecb42c8c 100644 --- a/src/main/java/org/traccar/protocol/ArnaviProtocol.java +++ b/src/main/java/org/traccar/protocol/ArnaviProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2020 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. @@ -15,9 +15,6 @@ */ package org.traccar.protocol; -import io.netty.handler.codec.LineBasedFrameDecoder; -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; @@ -28,10 +25,8 @@ public class ArnaviProtocol extends BaseProtocol { addServer(new TrackerServer(false, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new ArnaviTextProtocolDecoder(ArnaviProtocol.this)); + pipeline.addLast(new ArnaviFrameDecoder()); + pipeline.addLast(new ArnaviProtocolDecoder(ArnaviProtocol.this)); } }); } diff --git a/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java new file mode 100644 index 000000000..68a70c944 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java @@ -0,0 +1,49 @@ +/* + * Copyright 2020 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.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Protocol; + +import java.net.SocketAddress; + +public class ArnaviProtocolDecoder extends BaseProtocolDecoder { + + private final ArnaviTextProtocolDecoder textProtocolDecoder; + private final ArnaviBinaryProtocolDecoder binaryProtocolDecoder; + + public ArnaviProtocolDecoder(Protocol protocol) { + super(protocol); + textProtocolDecoder = new ArnaviTextProtocolDecoder(protocol); + binaryProtocolDecoder = new ArnaviBinaryProtocolDecoder(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (buf.getByte(buf.readerIndex()) == '$') { + return textProtocolDecoder.decode(channel, remoteAddress, msg); + } else { + return binaryProtocolDecoder.decode(channel, remoteAddress, msg); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java index 8c4f743bc..b99869e6e 100644 --- a/src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2020 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. @@ -15,6 +15,7 @@ */ package org.traccar.protocol; +import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.DeviceSession; @@ -25,6 +26,7 @@ import org.traccar.helper.PatternBuilder; import org.traccar.model.Position; import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; import java.util.regex.Pattern; public class ArnaviTextProtocolDecoder extends BaseProtocolDecoder { @@ -65,7 +67,8 @@ public class ArnaviTextProtocolDecoder extends BaseProtocolDecoder { protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - Parser parser = new Parser(PATTERN, (String) msg); + ByteBuf buf = (ByteBuf) msg; + Parser parser = new Parser(PATTERN, buf.toString(StandardCharsets.US_ASCII)); if (!parser.matches()) { return null; } diff --git a/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java index 065a28580..79179d4f3 100644 --- a/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java @@ -10,31 +10,31 @@ public class ArnaviTextProtocolDecoderTest extends ProtocolTest { ArnaviTextProtocolDecoder decoder = new ArnaviTextProtocolDecoder(null); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "$AV,V4,999999,12487,2277,203,65534,0,0,193,65535,65535,65535,65535,1,13,80.0,56.1,200741,5950.6773N,03029.1043E,300.0,360.0,121012,65535,65535,65535,SF*6E")); - verifyNull(decoder, text( + verifyNull(decoder, buffer( "$AV,V3DI,85164,20707,-1,19,0008C56A,000879AC,0C000002,863071013041618,89997077111301204297,*0B")); - verifyNull(decoder, text( + verifyNull(decoder, buffer( "$AV,V6SD,85164,20708,-1,3,6,37,33,*52")); - verifyAttributes(decoder, text( + verifyAttributes(decoder, buffer( "$AV,V4,85164,20709,1148,418,-1,0,1,192,0,0,0,0,0,0,,,000023,0000.0000N,00000.0000E,0.0,0.0,060180,0,0,32767,*4F")); - verifyNull(decoder, text( + verifyNull(decoder, buffer( "$AV,V3GSMINFO,85164,-1,20450,KMOBILE,1,2,1,23,0,40101,cc3,1,ce19,401,16,65304,5613,72,,SF*7F")); - verifyAttributes(decoder, text( + verifyAttributes(decoder, buffer( "$AV,V4,85164,20451,1146,418,-1,1,1,192,0,0,0,0,0,0,,,104340,0000.0000N,00000.0000E,0.0,0.0,060219,11,0,32767,,SF*47")); - verifyNull(decoder, text( + verifyNull(decoder, buffer( "$AV,V6SD,85164,20452,-1,3,3,5,6769,,SF*5D")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "$AV,V2,32768,12487,2277,203,-1,0,0,193,0,0,1,13,200741,5950.6773N,03029.1043E,0.0,0.0,121012,*6E")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "$AV,V3,999999,12487,2277,203,65534,0,0,193,65535,65535,65535,65535,1,13,200741,5950.6773N,03029.1043E,300.0,360.0,121012,65535,65535,65535,SF*6E")); } -- cgit v1.2.3 From 574566c160357f2e2cac45368ec363ab59952a6d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 2 Feb 2020 16:33:57 -0800 Subject: Fix checkstyle issue --- src/main/java/org/traccar/protocol/ArnaviFrameDecoder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/ArnaviFrameDecoder.java b/src/main/java/org/traccar/protocol/ArnaviFrameDecoder.java index 3db11113d..473e8b2c7 100644 --- a/src/main/java/org/traccar/protocol/ArnaviFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/ArnaviFrameDecoder.java @@ -59,7 +59,8 @@ public class ArnaviFrameDecoder extends BaseFrameDecoder { length = 4; } else { int index = 2; - while (index + PACKET_WRAPPER_LENGTH < buf.readableBytes() && buf.getByte(index) != PACKAGE_END_SIGN) { + while (index + PACKET_WRAPPER_LENGTH < buf.readableBytes() + && buf.getByte(index) != PACKAGE_END_SIGN) { index += PACKET_WRAPPER_LENGTH + buf.getUnsignedShortLE(index + 1); } if (buf.getByte(index) != PACKAGE_END_SIGN) { -- cgit v1.2.3 From 117189248da9cac8426d8fa4fb50f8a8d63f56b0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 3 Feb 2020 22:02:24 -0800 Subject: Fix Arnavi response --- src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java index 0924cfc40..d25c02414 100644 --- a/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java @@ -63,7 +63,8 @@ public class ArnaviBinaryProtocolDecoder extends BaseProtocolDecoder { response.writeByte(0x04); response.writeByte(0x00); ByteBuffer time = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)); - response.writeByte(Checksum.modulo256(time)); + time.position(0); + response.writeByte(Checksum.modulo256(time.slice())); response.writeBytes(time); } response.writeByte(0x7d); -- cgit v1.2.3 From b73cafaba31fb6165a6539bb795600642bd3899d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 3 Feb 2020 22:28:53 -0800 Subject: Decode input and output --- .../traccar/protocol/MeitrackProtocolDecoder.java | 28 +++++++++++----------- .../protocol/MeitrackProtocolDecoderTest.java | 3 +++ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 55260ef0c..529496928 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -70,7 +70,8 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { .number("(d+)|") // mnc .number("(x+)|") // lac .number("(x+),") // cid - .number("(x+),") // state + .number("(xx)") // input + .number("(xx),") // output .number("(x+)?|") // adc1 .number("(x+)?|") // adc2 .number("(x+)?|") // adc3 @@ -149,39 +150,38 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { } position.setDeviceId(deviceSession.getDeviceId()); - int event = parser.nextInt(0); + int event = parser.nextInt(); position.set(Position.KEY_EVENT, event); position.set(Position.KEY_ALARM, decodeAlarm(event)); - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); position.setTime(parser.nextDateTime()); position.setValid(parser.next().equals("A")); position.set(Position.KEY_SATELLITES, parser.nextInt()); - int rssi = parser.nextInt(0); + int rssi = parser.nextInt(); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + position.setCourse(parser.nextDouble()); position.set(Position.KEY_HDOP, parser.nextDouble()); - position.setAltitude(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble()); - position.set(Position.KEY_ODOMETER, parser.nextInt(0)); + position.set(Position.KEY_ODOMETER, parser.nextInt()); position.set("runtime", parser.next()); position.setNetwork(new Network(CellTower.from( - parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0), rssi))); + parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt(), rssi))); - position.set(Position.KEY_STATUS, parser.next()); + position.set(Position.KEY_OUTPUT, parser.nextHexInt()); + position.set(Position.KEY_INPUT, parser.nextHexInt()); for (int i = 1; i <= 3; i++) { - if (parser.hasNext()) { - position.set(Position.PREFIX_ADC + i, parser.nextHexInt(0)); - } + position.set(Position.PREFIX_ADC + i, parser.nextHexInt()); } String deviceModel = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getModel(); diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index 3e05d5243..9f9da26ca 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest { MeitrackProtocolDecoder decoder = new MeitrackProtocolDecoder(null); + verifyPosition(decoder, buffer( + "$$O160,863835028611502,AAA,35,7.887840,98.375193,200202020238,A,12,4,0,279,0.6,45,32121,442492,520|3|12DF|015273E2,0000,0000|0000|0000|018D|04F0,00000001,,1,0000*F3")); + verifyNull(decoder, binary( "242441313038362c3836343530373033313231393937342c4430302c3138303232343037323631345f4331453130395f4e31553144312e6a70672c31342c302cffd8ffdb008400140e0f120f0d14121012171514181e32211e1c1c1e3d2c2e243249404c4b47404645505a736250556d5645466488656d777b8182814e608d978c7d96737e817c011517171e1a1e3b21213b7c5346537c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7cffc000110801e0028003012100021101031101ffdd0004000affc401a20000010501010101010100000000000000000102030405060708090a0b100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9fa0100030101010101010101010000000000000102030405060708090a0b1100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00cca69ac8d06e3348569884db4845021b498a60371494008692980119a8ca7a5342101a5cd5221a0ab312ed1ee68b943e80dce2a467ffd0c806a48e592270f13b230e841a0096eeea7bb09e6c85b667033552800069c2980e14f15422418a916ad099228a95455089505584140993a2d5fb598a7cae72bd8fa536ae892e8e69e2b9d971168a459fffd1ece8a0028a006b534f4a68ce5b9130a89ab444919a61a6c634d34d21894952310d25002514084a4a00ffd2d2349564086929082929805250025140094940c4a4a04251400949408292819fffd3cca31591a098a5c62801a45464531098a69a6210d371400629a6980628eb400c64cd3791c1aa16c491479393563343105424fcc4d007ffd4c3463c0a94500381a5e3b8cd000c99e57f2a8f3835402834e0d4d08914d4aa6ac4c954d4aad4c4c955aa647a6496236ab51b552132e412e383d3f955b0722b09ab32a0c5a2a0d0ffd5ece8a0028a0061a6d5193dc8daa36ab422334c34c634")); -- cgit v1.2.3 From 20c2c9eaf19a30bf7cd3182ad3f09af6336404f9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 4 Feb 2020 21:20:53 -0800 Subject: Add content length --- .../java/org/traccar/protocol/GlobalstarProtocolDecoder.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java index 26af8d5af..14b1ff8c5 100644 --- a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2020 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. @@ -23,6 +23,7 @@ import io.netty.channel.Channel; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import org.traccar.BaseHttpProtocolDecoder; @@ -50,6 +51,7 @@ import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.Date; import java.util.LinkedList; @@ -103,20 +105,22 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { ByteBuf content = Unpooled.buffer(); transformer.transform(new DOMSource(document), new StreamResult(new ByteBufOutputStream(content))); - FullHttpResponse response = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content); if (channel != null) { + FullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content); + response.headers().add(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()); channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); } } - @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { FullHttpRequest request = (FullHttpRequest) msg; + sendResponse(channel, "test"); + Document document = documentBuilder.parse(new ByteBufferBackedInputStream(request.content().nioBuffer())); NodeList nodes = (NodeList) messageExpression.evaluate(document, XPathConstants.NODESET); -- cgit v1.2.3 From 211dffbcc7d6e43238e7560af968a018b410d60c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 4 Feb 2020 21:29:04 -0800 Subject: Fix build issue --- src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java index 14b1ff8c5..e2406881a 100644 --- a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java @@ -51,7 +51,6 @@ import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.Date; import java.util.LinkedList; -- cgit v1.2.3 From 7e9c68727d65c858264a493003f73195e4f51210 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 4 Feb 2020 22:04:48 -0800 Subject: Support old Java versions --- src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java index d25c02414..e957a6911 100644 --- a/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java @@ -27,6 +27,7 @@ import org.traccar.helper.Checksum; import org.traccar.model.Position; import java.net.SocketAddress; +import java.nio.Buffer; import java.nio.ByteBuffer; import java.util.Date; import java.util.LinkedList; @@ -63,7 +64,7 @@ public class ArnaviBinaryProtocolDecoder extends BaseProtocolDecoder { response.writeByte(0x04); response.writeByte(0x00); ByteBuffer time = ByteBuffer.allocate(4).putInt((int) (System.currentTimeMillis() / 1000)); - time.position(0); + ((Buffer) time).position(0); response.writeByte(Checksum.modulo256(time.slice())); response.writeBytes(time); } -- cgit v1.2.3 From 2c0563a4f7d4c89551c23c13f17249b5f1b4665a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 4 Feb 2020 22:33:53 -0800 Subject: Implement support for iButton --- .../java/org/traccar/protocol/SuntechProtocolDecoder.java | 15 +++++++++++++-- .../org/traccar/protocol/SuntechProtocolDecoderTest.java | 4 ++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java index 915f764e1..7e520ab3a 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java @@ -614,10 +614,21 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); } + int alertId = 0; if (BitUtil.check(mask, 19)) { - int value = buf.readUnsignedByte(); + alertId = buf.readUnsignedByte(); if (type == 0x82) { - position.set(Position.KEY_ALARM, decodeAlert(value)); + position.set(Position.KEY_ALARM, decodeAlert(alertId)); + } + } + + if (BitUtil.check(mask, 20)) { + buf.readUnsignedShort(); // alert mod + } + + if (BitUtil.check(mask, 21)) { + if (alertId == 59) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, ByteBufUtil.hexDump(buf.readSlice(8))); } } diff --git a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java index ad9be942f..82f0a29e1 100644 --- a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java @@ -62,6 +62,10 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { SuntechProtocolDecoder decoder = new SuntechProtocolDecoder(null); + verifyAttribute(decoder, binary( + "82004d05800000553fffff360100100114020410293902ccccf102dc007b00053c00476fa18469e87f000000000b0100003b00081d00000113f3f8010000049e00000000000000001d00000113f3f801"), + Position.KEY_DRIVER_UNIQUE_ID, "1d00000113f3f801"); + verifyPosition(decoder, buffer( "ST410STT;007638094;426;01;24153;724;4;-65;365;0;24161;724;4;365;0;0;24162;724;4;365;0;0;24363;724;4;365;0;0;24151;724;4;365;0;0;24991;724;4;365;0;0;24373;724;4;365;0;0;3.98;1;0176;2;016;20200106;19:18:04;-15.571860;-056.062637;000.852;238.28;6;1;201")); -- cgit v1.2.3 From eaacf2e139b15e8d8c25f15b2d1559245184fffa Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 5 Feb 2020 21:29:55 -0800 Subject: Cell info attributes --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 946652b03..6f4f9f75e 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -259,9 +259,16 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { int mcc = buf.readUnsignedShort(); int mnc = BitUtil.check(mcc, 15) ? buf.readUnsignedShort() : buf.readUnsignedByte(); + int lac = buf.readUnsignedShort(); + int cid = buf.readUnsignedMedium(); + + position.set("mcc", mcc); + position.set("mnc", mnc); + position.set("lac", lac); + position.set("cid", cid); position.setNetwork(new Network(CellTower.from( - BitUtil.to(mcc, 15), mnc, buf.readUnsignedShort(), buf.readUnsignedMedium()))); + BitUtil.to(mcc, 15), mnc, lac, cid))); if (length > 9) { buf.skipBytes(length - 9); -- cgit v1.2.3 From e193ae4656a6e0555565b35e8c657ae0777b156b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 6 Feb 2020 23:16:11 -0800 Subject: Decode additional data --- .../org/traccar/protocol/BlueProtocolDecoder.java | 30 +++++++++++++++++++++- .../traccar/protocol/BlueProtocolDecoderTest.java | 13 ++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/BlueProtocolDecoder.java b/src/main/java/org/traccar/protocol/BlueProtocolDecoder.java index 61edcd101..f35ac6fbe 100644 --- a/src/main/java/org/traccar/protocol/BlueProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/BlueProtocolDecoder.java @@ -66,6 +66,19 @@ public class BlueProtocolDecoder extends BaseProtocolDecoder { } } + private String decodeAlarm(int value) { + switch (value) { + case 1: + return Position.ALARM_SOS; + case 8: + return Position.ALARM_OVERSPEED; + case 19: + return Position.ALARM_LOW_POWER; + default: + return null; + } + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -123,10 +136,25 @@ public class BlueProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // status 2 buf.readUnsignedByte(); // status 3 - buf.readUnsignedByte(); // status 4 + + status = buf.readUnsignedByte(); // status 4 + int ignition = BitUtil.between(status, 2, 4); + if (ignition == 0b01) { + position.set(Position.KEY_IGNITION, false); + } + if (ignition == 0b10) { + position.set(Position.KEY_IGNITION, true); + } + buf.readUnsignedByte(); // status 5 buf.readUnsignedByte(); // status 6 + position.set(Position.KEY_STATUS, buf.readUnsignedShort()); + + } else if (type == 0x81) { + + position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + } else if (type == 0x84) { sendResponse(channel, index); diff --git a/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java index 9f3254824..4aa50e56b 100644 --- a/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java @@ -2,6 +2,7 @@ package org.traccar.protocol; import org.junit.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Position; public class BlueProtocolDecoderTest extends ProtocolTest { @@ -10,6 +11,18 @@ public class BlueProtocolDecoderTest extends ProtocolTest { BlueProtocolDecoder decoder = new BlueProtocolDecoder(null); + verifyAttribute(decoder, binary( + "AA0056860080E3E79E0C811F80000114020207170520011F00407F8005EE1938113B270000000000000000140202071705005AC7A621121F0002000100B7000080110000000000001A3A0000000001F400000000000078"), + Position.KEY_ALARM, Position.ALARM_SOS); + + verifyAttribute(decoder, binary( + "AA004A860080E3E79E20015FBE40148005EE193B113B263700000000000000140202080C09005AC7A621125F0002000000BB000000000000000000001A3A0007000001F400000000000008"), + Position.KEY_IGNITION, true); + + verifyAttribute(decoder, binary( + "AA004A860080E3E79E200160BE40148005EE193B113B263700000000000000140202080C13005AC7A62112600002000000B7000000110000000000001A3A0007000001F400000000000012"), + Position.KEY_STATUS, 0x11); + verifyPosition(decoder, binary( "aa00550000813f6f840b840380001032000000002001030040008005ee1938113b26f300000000000000140114082833044d27602112030002000000b70000020000000000000000650000001601f4000000000000e4")); -- cgit v1.2.3 From 33fdec9a234fc50eb430ce2342d779f5cf681fdc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 8 Feb 2020 10:45:19 -0800 Subject: Update version numbers --- build.gradle | 2 +- pom.xml | 2 +- setup/traccar.iss | 2 +- swagger.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index efb65314a..6aa6af8a7 100644 --- a/build.gradle +++ b/build.gradle @@ -91,7 +91,7 @@ jar { manifest { attributes( "Main-Class": "org.traccar.Main", - "Implementation-Version": "4.7", + "Implementation-Version": "4.8", "Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" ")) } } diff --git a/pom.xml b/pom.xml index f5eeedffb..535a20e6d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.traccar traccar - 4.7-SNAPSHOT + 4.8-SNAPSHOT traccar https://www.traccar.org diff --git a/setup/traccar.iss b/setup/traccar.iss index e66f38b6d..6dcad8e4d 100644 --- a/setup/traccar.iss +++ b/setup/traccar.iss @@ -1,6 +1,6 @@ [Setup] AppName=Traccar -AppVersion=4.7 +AppVersion=4.8 DefaultDirName={pf}\Traccar OutputBaseFilename=traccar-setup ArchitecturesInstallIn64BitMode=x64 diff --git a/swagger.json b/swagger.json index bf62510c4..e252d36c4 100644 --- a/swagger.json +++ b/swagger.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "version": "4.7", + "version": "4.8", "title": "traccar" }, "host": "demo.traccar.org", -- cgit v1.2.3 From 9b65e16b36e608c323c8e0b3d2566a511ec7655f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 8 Feb 2020 11:15:54 -0800 Subject: Change isetup version --- setup/environment.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/environment.sh b/setup/environment.sh index 5090bbfb7..5c2c16507 100644 --- a/setup/environment.sh +++ b/setup/environment.sh @@ -20,7 +20,7 @@ unzip SenchaCmd-*.zip ; rm SenchaCmd-*.zip export PATH=$PATH:~/bin/Sencha/Cmd/ cd traccar/setup -wget http://files.jrsoftware.org/is/5/isetup-5.5.8.exe +wget http://files.jrsoftware.org/is/5/isetup-5.5.6.exe wget https://github.com/ojdkbuild/ojdkbuild/releases/download/java-11-openjdk-debug-11.0.6.10-1/java-11-openjdk-debug-11.0.6.10-1.windows.ojdkbuild.x86_64.zip wget https://github.com/ojdkbuild/contrib_jdk11u-ci/releases/download/jdk-11.0.5%2B10/jdk-11.0.5-ojdkbuild-linux-x64.zip wget https://github.com/ojdkbuild/contrib_jdk11u-arm32-ci/releases/download/jdk-11.0.5%2B10/jdk-11.0.5-ojdkbuild-linux-armhf.zip -- cgit v1.2.3 From 533d5887d09f794d1d02fd5d8f3b14c480a10a67 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 8 Feb 2020 11:49:17 -0800 Subject: Update submodule commit --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index 5549ec84f..e8479d77f 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit 5549ec84fc341b1ea076720e4d18a709573f9ada +Subproject commit e8479d77f13acc3b3738a180a7990b06c495f1ba -- cgit v1.2.3 From d9d79d6e4900b144a66a3e85fdd78c4b9b0c9bd3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 9 Feb 2020 09:43:06 -0800 Subject: Add content type --- src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java index e2406881a..08f0c088d 100644 --- a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java @@ -107,7 +107,9 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { if (channel != null) { FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content); - response.headers().add(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()); + response.headers() + .add(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()) + .add(HttpHeaderNames.CONTENT_TYPE, "text/xml"); channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); } } -- cgit v1.2.3 From 9f074b062271e5e46612ef0149dd8e2269c22222 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 10 Feb 2020 22:45:25 -0800 Subject: Revert "Cell info attributes" This reverts commit eaacf2e1 --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 6f4f9f75e..946652b03 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -259,16 +259,9 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { int mcc = buf.readUnsignedShort(); int mnc = BitUtil.check(mcc, 15) ? buf.readUnsignedShort() : buf.readUnsignedByte(); - int lac = buf.readUnsignedShort(); - int cid = buf.readUnsignedMedium(); - - position.set("mcc", mcc); - position.set("mnc", mnc); - position.set("lac", lac); - position.set("cid", cid); position.setNetwork(new Network(CellTower.from( - BitUtil.to(mcc, 15), mnc, lac, cid))); + BitUtil.to(mcc, 15), mnc, buf.readUnsignedShort(), buf.readUnsignedMedium()))); if (length > 9) { buf.skipBytes(length - 9); -- cgit v1.2.3 From f144438bdcf1385d8f3e9dbd42b9b90e28f750e4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 10 Feb 2020 22:57:09 -0800 Subject: Support wifi networks --- .../org/traccar/protocol/HuaShengProtocolDecoder.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java index 920898039..eac06bbfe 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java @@ -28,6 +28,7 @@ import org.traccar.helper.UnitsConverter; import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; @@ -139,6 +140,8 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ODOMETER, buf.readUnsignedShort() * 1000); + Network network = new Network(); + while (buf.readableBytes() > 4) { int subtype = buf.readUnsignedShort(); int length = buf.readUnsignedShort() - 4; @@ -164,7 +167,6 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); break; case 0x0020: - Network network = new Network(); String[] cells = buf.readCharSequence( length, StandardCharsets.US_ASCII).toString().split("\\+"); for (String cell : cells) { @@ -173,7 +175,14 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { Integer.parseInt(values[0]), Integer.parseInt(values[1]), Integer.parseInt(values[2], 16), Integer.parseInt(values[3], 16))); } - position.setNetwork(network); + break; + case 0x0021: + String[] points = buf.readCharSequence( + length, StandardCharsets.US_ASCII).toString().split("\\+"); + for (String point : points) { + String[] values = point.split("@"); + network.addWifiAccessPoint(WifiAccessPoint.from(values[0], Integer.parseInt(values[1]))); + } break; default: buf.skipBytes(length); @@ -181,6 +190,10 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { } } + if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) { + position.setNetwork(network); + } + sendResponse(channel, MSG_POSITION_RSP, index, null); return position; -- cgit v1.2.3 From 83618b94c380b2f31b65eba20ee295c824cd2726 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 10 Feb 2020 23:10:23 -0800 Subject: Fix response message --- .../org/traccar/protocol/GatorProtocolDecoder.java | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java index 043839be9..cce23288a 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2020 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. @@ -23,6 +23,7 @@ import org.traccar.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.BcdUtil; +import org.traccar.helper.Checksum; import org.traccar.helper.DateBuilder; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; @@ -58,16 +59,16 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder { return String.format("%02d%02d%02d%02d%02d", d1, d2, d3, d4, d5); } - private void sendResponse(Channel channel, SocketAddress remoteAddress, byte calibration) { + private void sendResponse(Channel channel, SocketAddress remoteAddress, int type, int checksum) { if (channel != null) { ByteBuf response = Unpooled.buffer(); - response.writeByte(0x24); response.writeByte(0x24); // header - response.writeByte(MSG_HEARTBEAT); // size - response.writeShort(5); - response.writeByte(calibration); - response.writeByte(0); // main order - response.writeByte(0); // slave order - response.writeByte(1); // calibration + response.writeShort(0x2424); // header + response.writeByte(MSG_HEARTBEAT); + response.writeShort(5); // length + response.writeByte(checksum); + response.writeByte(type); + response.writeByte(0); // subtype + response.writeByte(Checksum.sum(response.nioBuffer(2, response.writerIndex()))); response.writeByte(0x0D); channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } @@ -87,7 +88,7 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - sendResponse(channel, remoteAddress, buf.getByte(buf.writerIndex() - 2)); + sendResponse(channel, remoteAddress, type, buf.getByte(buf.writerIndex() - 2)); if (type == MSG_POSITION_DATA || type == MSG_ROLLCALL_RESPONSE || type == MSG_ALARM_DATA || type == MSG_BLIND_AREA) { -- cgit v1.2.3 From c860f15e6a541c72d901d928941912edb943883e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 15 Feb 2020 11:01:15 -0800 Subject: Fix checksum calculation --- src/main/java/org/traccar/protocol/GatorProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java index cce23288a..087861635 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -68,7 +68,7 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder { response.writeByte(checksum); response.writeByte(type); response.writeByte(0); // subtype - response.writeByte(Checksum.sum(response.nioBuffer(2, response.writerIndex()))); + response.writeByte(Checksum.xor(response.nioBuffer(2, response.writerIndex()))); response.writeByte(0x0D); channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } -- cgit v1.2.3 From 8bf4c171e1771eb89506a87ba8435776ee61286e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 15 Feb 2020 11:11:01 -0800 Subject: Fix ADC decoding --- src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java | 2 +- src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java index 7e520ab3a..978d768be 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java @@ -397,7 +397,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { if (isIncludeAdc(deviceSession.getDeviceId())) { for (int i = 1; i <= 3; i++) { - if (!values[index++].isEmpty()) { + if (index < values.length && !values[index++].isEmpty()) { position.set(Position.PREFIX_ADC + i, Double.parseDouble(values[index - 1])); } } diff --git a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java index 82f0a29e1..692a13131 100644 --- a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java @@ -13,6 +13,11 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { decoder.setHbm(true); decoder.setIncludeAdc(true); + + verifyAttribute(decoder, buffer( + "ST600STT;008594432;20;492;20200212;18:58:30;060bb0e1;334;20;36bb;45;+19.337897;-099.064489;000.398;000.00;12;1;5049883;13.61;100100;2;1198;013762;4.2;1;4.68"), + Position.PREFIX_ADC + 1, 4.68); + decoder.setIncludeTemp(true); verifyAttribute(decoder, buffer( -- cgit v1.2.3 From 81858280f7477da619aaf1adca972827847b47cb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 15 Feb 2020 11:16:43 -0800 Subject: Decode driving behavior --- src/main/java/org/traccar/protocol/BceProtocolDecoder.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java index c71cdffd9..68d4447ec 100644 --- a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2020 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. @@ -217,9 +217,9 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedShortLE(); } if (BitUtil.check(mask, 6)) { - buf.readUnsignedByte(); // maximum acceleration - buf.readUnsignedByte(); // maximum deceleration - buf.readUnsignedByte(); // maximum cornering + position.set("maxAcceleration", buf.readUnsignedByte()); + position.set("maxBraking", buf.readUnsignedByte()); + position.set("maxCornering", buf.readUnsignedByte()); } if (BitUtil.check(mask, 7)) { buf.skipBytes(16); -- cgit v1.2.3 From f8c83c4f7f517b7482bdf7f29a3704903b876855 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Sat, 15 Feb 2020 20:23:08 -0500 Subject: Changes after review --- src/main/java/org/traccar/MainModule.java | 7 +++ src/main/java/org/traccar/WebDataHandler.java | 64 +++++++++++++-------------- src/main/java/org/traccar/config/Keys.java | 32 +++++++------- 3 files changed, 54 insertions(+), 49 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 3acd19b6a..24448ef51 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -73,6 +73,7 @@ import org.traccar.reports.model.TripsConfig; import javax.annotation.Nullable; import javax.ws.rs.client.Client; +import io.netty.util.Timer; public class MainModule extends AbstractModule { @@ -375,6 +376,12 @@ public class MainModule extends AbstractModule { return new DriverEventHandler(identityManager); } + @Singleton + @Provides + public static Timer provideGlobalTimer() { + return GlobalTimer.getTimer(); + } + @Override protected void configure() { binder().requireExplicitBindings(); diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java index e2f7c1e8b..58b9ca73b 100644 --- a/src/main/java/org/traccar/WebDataHandler.java +++ b/src/main/java/org/traccar/WebDataHandler.java @@ -18,6 +18,7 @@ package org.traccar; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.channel.ChannelHandler; +import io.netty.util.Timer; import io.netty.util.Timeout; import io.netty.util.TimerTask; import org.slf4j.Logger; @@ -66,11 +67,11 @@ public class WebDataHandler extends BaseDataHandler { private final boolean json; private final boolean retryEnabled; - private final int retryDelayMin; - private final int retryDelayMax; - private final int deliveryPendingLimit; + private final int retryDelay; + private final int retryCount; + private final int retryLimit; - private AtomicInteger deliveryPendingCurrent; + private AtomicInteger deliveryPending; @Inject public WebDataHandler( @@ -84,11 +85,11 @@ public class WebDataHandler extends BaseDataHandler { this.json = config.getBoolean(Keys.FORWARD_JSON); this.retryEnabled = config.getBoolean(Keys.FORWARD_RETRY_ENABLE); - this.retryDelayMin = config.getInteger(Keys.FORWARD_RETRY_DELAY_MIN, 1); - this.retryDelayMax = config.getInteger(Keys.FORWARD_RETRY_DELAY_MAX, 10); - this.deliveryPendingLimit = config.getInteger(Keys.FORWARD_RETRY_PENDING_LIMIT, 100); + this.retryDelay = config.getInteger(Keys.FORWARD_RETRY_DELAY, 100); + this.retryCount = config.getInteger(Keys.FORWARD_RETRY_COUNT, 10); + this.retryLimit = config.getInteger(Keys.FORWARD_RETRY_LIMIT, 100); - this.deliveryPendingCurrent = new AtomicInteger(0); + this.deliveryPending = new AtomicInteger(0); } private static String formatSentence(Position position) { @@ -183,7 +184,7 @@ public class WebDataHandler extends BaseDataHandler { class AsyncRequestAndCallback implements InvocationCallback { - private int delay = retryDelayMin; + private int retries = 0; private Map payload; private Invocation.Builder requestBuilder; @@ -208,7 +209,7 @@ public class WebDataHandler extends BaseDataHandler { payload = prepareJsonPayload(position); } - deliveryPendingCurrent.incrementAndGet(); + deliveryPending.incrementAndGet(); send(); } @@ -222,40 +223,37 @@ public class WebDataHandler extends BaseDataHandler { } private void retry() { + boolean ok = false; try { - String message = "Position forwarding failed."; - if (!retryEnabled) { - LOGGER.warn(message); - } else { - int pending = deliveryPendingCurrent.get(); - if (pending <= deliveryPendingLimit) { - LOGGER.warn(message + " Pending: " + pending - + ". Retrying in " + delay + " seconds."); - GlobalTimer.getTimer().newTimeout(new TimerTask() { - @Override - public void run(Timeout timeout) { + if (retryEnabled && deliveryPending.get() <= retryLimit && retries < retryCount) { + Main.getInjector().getInstance(Timer.class).newTimeout(new TimerTask() { + @Override + public void run(Timeout timeout) { + boolean ok = false; + try { if (!timeout.isCancelled()) { - if (delay < retryDelayMax) { - delay++; - } send(); + ok = true; + } + } finally { + if (!ok) { + deliveryPending.decrementAndGet(); } } - }, delay, TimeUnit.SECONDS); - return; - } - LOGGER.warn(message + " Pending: " + pending - + ". Delivery will not be retried."); + } + }, retryDelay * (int) Math.pow(2, retries++), TimeUnit.MILLISECONDS); + ok = true; } - } catch (Exception e) { + } finally { + int pending = ok ? deliveryPending.get() : deliveryPending.decrementAndGet(); + LOGGER.warn("Position forwarding failed: " + pending + " pending"); } - deliveryPendingCurrent.decrementAndGet(); } @Override public void completed(Response response) { - if (response.getStatus() == 200) { - deliveryPendingCurrent.decrementAndGet(); + if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) { + deliveryPending.decrementAndGet(); } else { retry(); } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 999a1d6df..d88b36d28 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -101,35 +101,35 @@ public final class Keys { "forward.json", Boolean.class); /** - * Position forwarding retrying enable. When enabled, additional attempts are made to deliver positions. - * If initial delivery fails, because of an unreachable server or an HTTP response different from '200 OK', - * the software waits for 'forward.retry.delay.min' seconds to retry delivery. On subsequent failures, this - * delay is incremented by 1 second up to 'forward.retry.delay.max'. Positions pending to be delivered - * are limited to 'forward.retry.pending.limit'. If this limit is reached, positions get discarded. + * Position forwarding retrying enable. When enabled, additional attempts are made to deliver positions. If initial + * delivery fails, because of an unreachable server or an HTTP response different from '2xx', the software waits + * for 'forward.retry.delay' milliseconds to retry delivery. On subsequent failures, this delay is duplicated. + * If forwarding is retried for 'forward.retry.count', retrying is canceled and the position is dropped. Positions + * pending to be delivered are limited to 'forward.retry.limit'. If this limit is reached, positions get discarded. */ public static final ConfigKey FORWARD_RETRY_ENABLE = new ConfigKey( "forward.retry.enable", Boolean.class); /** - * Position forwarding retry minimum delay in seconds. - * Can be set to anything greater than 0. Defaults to 1 second. + * Position forwarding retry first delay in milliseconds. + * Can be set to anything greater than 0. Defaults to 100 milliseconds. */ - public static final ConfigKey FORWARD_RETRY_DELAY_MIN = new ConfigKey( - "forward.retry.delay.min", Integer.class); + public static final ConfigKey FORWARD_RETRY_DELAY = new ConfigKey( + "forward.retry.delay", Integer.class); /** - * Position forwarding retry maximum delay in seconds. - * Can be set to anything greater than 0. Defaults to 10 seconds. + * Position forwarding retry maximum retries. + * Can be set to anything greater than 0. Defaults to 10 retries. */ - public static final ConfigKey FORWARD_RETRY_DELAY_MAX = new ConfigKey( - "forward.retry.delay.max", Integer.class); + public static final ConfigKey FORWARD_RETRY_COUNT = new ConfigKey( + "forward.retry.count", Integer.class); /** - * Position forwarding retry pending limit. + * Position forwarding retry pending positions limit. * Can be set to anything greater than 0. Defaults to 100 positions. */ - public static final ConfigKey FORWARD_RETRY_PENDING_LIMIT = new ConfigKey( - "forward.retry.pending.limit", Integer.class); + public static final ConfigKey FORWARD_RETRY_LIMIT = new ConfigKey( + "forward.retry.limit", Integer.class); /** * Boolean flag to enable or disable position filtering. -- cgit v1.2.3 From b6fe2bd75a3541d6fe63a6b6161ed04b773e37a6 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 15 Feb 2020 21:50:18 -0800 Subject: Provide default URL --- src/main/java/org/traccar/geocoder/OpenCageGeocoder.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java b/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java index 822b6e91e..56161e52c 100644 --- a/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java +++ b/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java @@ -1,6 +1,6 @@ /* * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com) - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 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. @@ -21,8 +21,16 @@ import javax.json.JsonObject; public class OpenCageGeocoder extends JsonGeocoder { + private static String formatUrl(String url, String key) { + if (url == null) { + url = "https://api.opencagedata.com/geocode/v1"; + } + url += "/json?q=%f,%f&no_annotations=1&key=" + key; + return url; + } + public OpenCageGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { - super(url + "/json?q=%f,%f&no_annotations=1&key=" + key, cacheSize, addressFormat); + super(formatUrl(url, key), cacheSize, addressFormat); } @Override -- cgit v1.2.3 From d199eb36f3b70d80f0a2cffead5777c7998c4e31 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 15 Feb 2020 22:01:58 -0800 Subject: Provide default URLs --- src/main/java/org/traccar/geocoder/FactualGeocoder.java | 12 ++++++++++-- src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java | 12 ++++++++---- src/main/java/org/traccar/geocoder/MapQuestGeocoder.java | 12 ++++++++++-- src/test/java/org/traccar/geocoder/GeocoderTest.java | 2 +- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/traccar/geocoder/FactualGeocoder.java b/src/main/java/org/traccar/geocoder/FactualGeocoder.java index c7a68c293..f540eb8fe 100644 --- a/src/main/java/org/traccar/geocoder/FactualGeocoder.java +++ b/src/main/java/org/traccar/geocoder/FactualGeocoder.java @@ -1,6 +1,6 @@ /* * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com) - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 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. @@ -20,8 +20,16 @@ import javax.json.JsonObject; public class FactualGeocoder extends JsonGeocoder { + private static String formatUrl(String url, String key) { + if (url == null) { + url = "https://api.factual.com/geotag"; + } + url += "?latitude=%f&longitude=%f&KEY=" + key; + return url; + } + public FactualGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { - super(url + "?latitude=%f&longitude=%f&KEY=" + key, cacheSize, addressFormat); + super(formatUrl(url, key), cacheSize, addressFormat); } @Override diff --git a/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java b/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java index 3a173f985..b4881a006 100644 --- a/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java +++ b/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2020 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. @@ -19,12 +19,16 @@ import javax.json.JsonObject; public class GisgraphyGeocoder extends JsonGeocoder { - public GisgraphyGeocoder(AddressFormat addressFormat) { - this("http://services.gisgraphy.com/reversegeocoding/search", 0, addressFormat); + private static String formatUrl(String url) { + if (url == null) { + url = "http://services.gisgraphy.com/reversegeocoding/search"; + } + url += "?format=json&lat=%f&lng=%f&from=1&to=1"; + return url; } public GisgraphyGeocoder(String url, int cacheSize, AddressFormat addressFormat) { - super(url + "?format=json&lat=%f&lng=%f&from=1&to=1", cacheSize, addressFormat); + super(formatUrl(url), cacheSize, addressFormat); } @Override diff --git a/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java b/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java index 4029e3f07..8dc3f76f0 100644 --- a/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java +++ b/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java @@ -1,6 +1,6 @@ /* * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com) - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 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. @@ -21,8 +21,16 @@ import javax.json.JsonObject; public class MapQuestGeocoder extends JsonGeocoder { + private static String formatUrl(String url, String key) { + if (url == null) { + url = "http://www.mapquestapi.com/geocoding/v1/reverse"; + } + url += "?key=" + key + "&location=%f,%f"; + return url; + } + public MapQuestGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { - super(url + "?key=" + key + "&location=%f,%f", cacheSize, addressFormat); + super(formatUrl(url, key), cacheSize, addressFormat); } @Override diff --git a/src/test/java/org/traccar/geocoder/GeocoderTest.java b/src/test/java/org/traccar/geocoder/GeocoderTest.java index 9f59d0b23..e70719b89 100644 --- a/src/test/java/org/traccar/geocoder/GeocoderTest.java +++ b/src/test/java/org/traccar/geocoder/GeocoderTest.java @@ -32,7 +32,7 @@ public class GeocoderTest { @Ignore @Test public void testGisgraphy() { - Geocoder geocoder = new GisgraphyGeocoder(new AddressFormat()); + Geocoder geocoder = new GisgraphyGeocoder(null, 0, new AddressFormat()); String address = geocoder.getAddress(48.8530000, 2.3400000, null); assertEquals("Rue du Jardinet, Paris, ÃŽle-de-France, FR", address); } -- cgit v1.2.3 From 4512941667653c15a28e0917024c04b73238005a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 18 Feb 2020 21:27:12 -0800 Subject: Convert decoded values --- src/main/java/org/traccar/protocol/BceProtocolDecoder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java index 68d4447ec..54136382c 100644 --- a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java @@ -113,7 +113,7 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte()); } if (BitUtil.check(mask, 4)) { - position.set(Position.KEY_RPM, buf.readUnsignedShortLE()); + position.set(Position.KEY_RPM, buf.readUnsignedShortLE() * 0.0125); } if (BitUtil.check(mask, 5)) { position.set(Position.KEY_HOURS, buf.readUnsignedIntLE()); @@ -122,7 +122,7 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); } if (BitUtil.check(mask, 7)) { - position.set(Position.KEY_COOLANT_TEMP, (int) buf.readByte()); + position.set(Position.KEY_COOLANT_TEMP, buf.readByte() - 40); } if (BitUtil.check(mask, 8)) { position.set("fuel2", buf.readUnsignedByte()); -- cgit v1.2.3 From 0f4695199a9a6c212bbe7021aa11db775eb2b7e5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 18 Feb 2020 21:39:04 -0800 Subject: Support UDP protocol --- src/main/java/org/traccar/protocol/EskyProtocol.java | 10 +++++++++- src/main/java/org/traccar/protocol/EskyProtocolDecoder.java | 11 +++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/EskyProtocol.java b/src/main/java/org/traccar/protocol/EskyProtocol.java index aaa92da58..fb047c207 100644 --- a/src/main/java/org/traccar/protocol/EskyProtocol.java +++ b/src/main/java/org/traccar/protocol/EskyProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 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. @@ -33,6 +33,14 @@ public class EskyProtocol extends BaseProtocol { pipeline.addLast(new EskyProtocolDecoder(EskyProtocol.this)); } }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new EskyProtocolDecoder(EskyProtocol.this)); + } + }); } } diff --git a/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java b/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java index 641b2e28f..d9de110f4 100644 --- a/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 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. @@ -16,8 +16,10 @@ package org.traccar.protocol; import io.netty.channel.Channel; +import io.netty.channel.socket.DatagramChannel; 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; @@ -35,7 +37,7 @@ public class EskyProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN = new PatternBuilder() .expression("..;") // header - .number("d+;") // index + .number("(d+);") // index .number("(d+);") // imei .text("R;") // data type .number("(d+)[+;]") // satellites @@ -63,6 +65,11 @@ public class EskyProtocolDecoder extends BaseProtocolDecoder { return null; } + int index = parser.nextInt(); + if (channel instanceof DatagramChannel) { + channel.writeAndFlush(new NetworkMessage("ACK," + index + "#", remoteAddress)); + } + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); if (deviceSession == null) { return null; -- cgit v1.2.3 From 1bbd6f12b34eaed8699fe943130142d9f2638df8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 19 Feb 2020 23:00:06 -0800 Subject: Remove test confirmation --- src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java index 08f0c088d..382509793 100644 --- a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java @@ -120,8 +120,6 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { FullHttpRequest request = (FullHttpRequest) msg; - sendResponse(channel, "test"); - Document document = documentBuilder.parse(new ByteBufferBackedInputStream(request.content().nioBuffer())); NodeList nodes = (NodeList) messageExpression.evaluate(document, XPathConstants.NODESET); -- cgit v1.2.3 From cb25fe3e58c0876fe6c000a1f0a7c7435e3fb0e1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 21 Feb 2020 21:54:45 -0800 Subject: Update readme file --- setup/README.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/setup/README.txt b/setup/README.txt index c50b392e2..ea8ea7a84 100644 --- a/setup/README.txt +++ b/setup/README.txt @@ -5,9 +5,6 @@ Installation instructions are available on the official website: Windows - https://www.traccar.org/windows/ Linux - https://www.traccar.org/linux/ Docker - https://www.traccar.org/docker/ -OS X - https://www.traccar.org/mac-os/ -OpenBSD - https://www.traccar.org/openbsd/ -FreeBSD - https://www.traccar.org/freebsd/ Other - https://www.traccar.org/manual-installation/ If you have any questions or problems visit support page: -- cgit v1.2.3 From deb519ebd6798450509afaf4067e140edd7eb0d0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 22 Feb 2020 11:34:57 -0800 Subject: Fix concurrency issues --- .../org/traccar/api/ExtendedObjectResource.java | 2 +- .../org/traccar/database/BaseObjectManager.java | 60 +++++++++-- .../java/org/traccar/database/CommandsManager.java | 29 ++++- .../java/org/traccar/database/DeviceManager.java | 118 +++++++++++++++------ .../java/org/traccar/database/DriversManager.java | 51 ++++++--- .../traccar/database/ExtendedObjectManager.java | 78 +++++++++----- .../java/org/traccar/database/GroupsManager.java | 5 +- .../org/traccar/database/SimpleObjectManager.java | 30 +++--- .../java/org/traccar/database/UsersManager.java | 6 +- 9 files changed, 276 insertions(+), 103 deletions(-) diff --git a/src/main/java/org/traccar/api/ExtendedObjectResource.java b/src/main/java/org/traccar/api/ExtendedObjectResource.java index 007a7b1bd..9e554217e 100644 --- a/src/main/java/org/traccar/api/ExtendedObjectResource.java +++ b/src/main/java/org/traccar/api/ExtendedObjectResource.java @@ -55,8 +55,8 @@ public class ExtendedObjectResource extends BaseObjectResou Context.getPermissionsManager().checkDevice(getUserId(), deviceId); result.retainAll(manager.getDeviceItems(deviceId)); } - return manager.getItems(result); + return manager.getItems(result); } } diff --git a/src/main/java/org/traccar/database/BaseObjectManager.java b/src/main/java/org/traccar/database/BaseObjectManager.java index 8bf9ef860..e274e5aba 100644 --- a/src/main/java/org/traccar/database/BaseObjectManager.java +++ b/src/main/java/org/traccar/database/BaseObjectManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,6 +23,8 @@ import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,6 +34,8 @@ public class BaseObjectManager { private static final Logger LOGGER = LoggerFactory.getLogger(BaseObjectManager.class); + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private final DataManager dataManager; private Map items; @@ -43,6 +47,22 @@ public class BaseObjectManager { refreshItems(); } + protected final void readLock() { + lock.readLock().lock(); + } + + protected final void readUnlock() { + lock.readLock().unlock(); + } + + protected final void writeLock() { + lock.writeLock().lock(); + } + + protected final void writeUnlock() { + lock.writeLock().unlock(); + } + protected final DataManager getDataManager() { return dataManager; } @@ -52,12 +72,18 @@ public class BaseObjectManager { } public T getById(long itemId) { - return items.get(itemId); + try { + readLock(); + return items.get(itemId); + } finally { + readUnlock(); + } } public void refreshItems() { if (dataManager != null) { try { + writeLock(); Collection databaseItems = dataManager.getObjects(baseClass); if (items == null) { items = new ConcurrentHashMap<>(databaseItems.size()); @@ -78,12 +104,19 @@ public class BaseObjectManager { } } catch (SQLException error) { LOGGER.warn("Error refreshing items", error); + } finally { + writeUnlock(); } } } protected void addNewItem(T item) { - items.put(item.getId(), item); + try { + writeLock(); + items.put(item.getId(), item); + } finally { + writeUnlock(); + } } public void addItem(T item) throws SQLException { @@ -92,7 +125,12 @@ public class BaseObjectManager { } protected void updateCachedItem(T item) { - items.put(item.getId(), item); + try { + writeLock(); + items.put(item.getId(), item); + } finally { + writeUnlock(); + } } public void updateItem(T item) throws SQLException { @@ -101,7 +139,12 @@ public class BaseObjectManager { } protected void removeCachedItem(long itemId) { - items.remove(itemId); + try { + writeLock(); + items.remove(itemId); + } finally { + writeUnlock(); + } } public void removeItem(long itemId) throws SQLException { @@ -121,7 +164,12 @@ public class BaseObjectManager { } public Set getAllItems() { - return items.keySet(); + try { + readLock(); + return items.keySet(); + } finally { + readUnlock(); + } } } diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java index dc9512d9e..de6eeeba8 100644 --- a/src/main/java/org/traccar/database/CommandsManager.java +++ b/src/main/java/org/traccar/database/CommandsManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -142,14 +142,33 @@ public class CommandsManager extends ExtendedObjectManager { } private Queue getDeviceQueue(long deviceId) { - if (!deviceQueues.containsKey(deviceId)) { - deviceQueues.put(deviceId, new ConcurrentLinkedQueue()); + Queue deviceQueue; + try { + readLock(); + deviceQueue = deviceQueues.get(deviceId); + } finally { + readUnlock(); + } + if (deviceQueue != null) { + return deviceQueue; + } else { + try { + writeLock(); + return deviceQueues.computeIfAbsent(deviceId, key -> new ConcurrentLinkedQueue<>()); + } finally { + writeUnlock(); + } } - return deviceQueues.get(deviceId); } public void sendQueuedCommands(ActiveDevice activeDevice) { - Queue deviceQueue = deviceQueues.get(activeDevice.getDeviceId()); + Queue deviceQueue; + try { + readLock(); + deviceQueue = deviceQueues.get(activeDevice.getDeviceId()); + } finally { + readUnlock(); + } if (deviceQueue != null) { Command command = deviceQueue.poll(); while (command != null) { diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index fa95adeb2..fe17f7ced 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2020 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. @@ -58,11 +58,16 @@ public class DeviceManager extends BaseObjectManager implements Identity public DeviceManager(DataManager dataManager) { super(dataManager, Device.class); this.config = Context.getConfig(); - if (devicesByPhone == null) { - devicesByPhone = new ConcurrentHashMap<>(); - } - if (devicesByUniqueId == null) { - devicesByUniqueId = new ConcurrentHashMap<>(); + try { + writeLock(); + if (devicesByPhone == null) { + devicesByPhone = new ConcurrentHashMap<>(); + } + if (devicesByUniqueId == null) { + devicesByUniqueId = new ConcurrentHashMap<>(); + } + } finally { + writeUnlock(); } dataRefreshDelay = config.getLong("database.refreshDelay", DEFAULT_REFRESH_DELAY) * 1000; lookupGroupsAttribute = config.getBoolean("deviceManager.lookupGroupsAttribute"); @@ -108,11 +113,20 @@ public class DeviceManager extends BaseObjectManager implements Identity @Override public Device getByUniqueId(String uniqueId) throws SQLException { - boolean forceUpdate = !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean("database.ignoreUnknown"); - + boolean forceUpdate; + try { + readLock(); + forceUpdate = !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean("database.ignoreUnknown"); + } finally { + readUnlock(); + } updateDeviceCache(forceUpdate); - - return devicesByUniqueId.get(uniqueId); + try { + readLock(); + return devicesByUniqueId.get(uniqueId); + } finally { + readUnlock(); + } } @Override @@ -134,7 +148,12 @@ public class DeviceManager extends BaseObjectManager implements Identity } public Device getDeviceByPhone(String phone) { - return devicesByPhone.get(phone); + try { + readLock(); + return devicesByPhone.get(phone); + } finally { + readUnlock(); + } } @Override @@ -176,8 +195,7 @@ public class DeviceManager extends BaseObjectManager implements Identity } public Set getAllManagedItems(long userId) { - Set result = new HashSet<>(); - result.addAll(getAllUserItems(userId)); + Set result = new HashSet<>(getAllUserItems(userId)); for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { result.addAll(getAllUserItems(managedUserId)); } @@ -186,34 +204,68 @@ public class DeviceManager extends BaseObjectManager implements Identity @Override public Set getManagedItems(long userId) { - Set result = new HashSet<>(); - result.addAll(getUserItems(userId)); + Set result = new HashSet<>(getUserItems(userId)); for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { result.addAll(getUserItems(managedUserId)); } return result; } - private void putUniqueDeviceId(Device device) { - if (devicesByUniqueId == null) { - devicesByUniqueId = new ConcurrentHashMap<>(getAllItems().size()); + private void addByUniqueId(Device device) { + try { + writeLock(); + if (devicesByUniqueId == null) { + devicesByUniqueId = new ConcurrentHashMap<>(); + } + devicesByUniqueId.put(device.getUniqueId(), device); + } finally { + writeUnlock(); + } + } + + private void removeByUniqueId(String deviceUniqueId) { + try { + writeLock(); + if (devicesByUniqueId != null) { + devicesByUniqueId.remove(deviceUniqueId); + } + } finally { + writeUnlock(); + } + } + + private void addByPhone(Device device) { + try { + writeLock(); + if (devicesByPhone == null) { + devicesByPhone = new ConcurrentHashMap<>(); + } + devicesByPhone.put(device.getPhone(), device); + } finally { + writeUnlock(); } - devicesByUniqueId.put(device.getUniqueId(), device); } - private void putPhone(Device device) { - if (devicesByPhone == null) { - devicesByPhone = new ConcurrentHashMap<>(getAllItems().size()); + private void removeByPhone(String phone) { + if (phone == null || phone.isEmpty()) { + return; + } + try { + writeLock(); + if (devicesByPhone != null) { + devicesByPhone.remove(phone); + } + } finally { + writeUnlock(); } - devicesByPhone.put(device.getPhone(), device); } @Override protected void addNewItem(Device device) { super.addNewItem(device); - putUniqueDeviceId(device); + addByUniqueId(device); if (device.getPhone() != null && !device.getPhone().isEmpty()) { - putPhone(device); + addByPhone(device); } if (Context.getGeofenceManager() != null) { Position lastPosition = getLastPosition(device.getId()); @@ -234,18 +286,16 @@ public class DeviceManager extends BaseObjectManager implements Identity cachedDevice.setDisabled(device.getDisabled()); cachedDevice.setAttributes(device.getAttributes()); if (!device.getUniqueId().equals(cachedDevice.getUniqueId())) { - devicesByUniqueId.remove(cachedDevice.getUniqueId()); + removeByUniqueId(cachedDevice.getUniqueId()); cachedDevice.setUniqueId(device.getUniqueId()); - putUniqueDeviceId(cachedDevice); + addByUniqueId(cachedDevice); } if (device.getPhone() != null && !device.getPhone().isEmpty() && !device.getPhone().equals(cachedDevice.getPhone())) { String phone = cachedDevice.getPhone(); - if (phone != null && !phone.isEmpty()) { - devicesByPhone.remove(phone); - } + removeByPhone(phone); cachedDevice.setPhone(device.getPhone()); - putPhone(cachedDevice); + addByPhone(cachedDevice); } } @@ -256,10 +306,8 @@ public class DeviceManager extends BaseObjectManager implements Identity String deviceUniqueId = cachedDevice.getUniqueId(); String phone = cachedDevice.getPhone(); super.removeCachedItem(deviceId); - devicesByUniqueId.remove(deviceUniqueId); - if (phone != null && !phone.isEmpty()) { - devicesByPhone.remove(phone); - } + removeByUniqueId(deviceUniqueId); + removeByPhone(phone); } positions.remove(deviceId); } diff --git a/src/main/java/org/traccar/database/DriversManager.java b/src/main/java/org/traccar/database/DriversManager.java index 930951460..d111cd643 100644 --- a/src/main/java/org/traccar/database/DriversManager.java +++ b/src/main/java/org/traccar/database/DriversManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,22 +27,44 @@ public class DriversManager extends ExtendedObjectManager { public DriversManager(DataManager dataManager) { super(dataManager, Driver.class); - if (driversByUniqueId == null) { - driversByUniqueId = new ConcurrentHashMap<>(); + try { + writeLock(); + if (driversByUniqueId == null) { + driversByUniqueId = new ConcurrentHashMap<>(); + } + } finally { + writeUnlock(); } } - private void putUniqueDriverId(Driver driver) { - if (driversByUniqueId == null) { - driversByUniqueId = new ConcurrentHashMap<>(getAllItems().size()); + private void addByUniqueId(Driver driver) { + try { + writeLock(); + if (driversByUniqueId == null) { + driversByUniqueId = new ConcurrentHashMap<>(); + } + driversByUniqueId.put(driver.getUniqueId(), driver); + } finally { + writeUnlock(); + } + } + + private void removeByUniqueId(String driverUniqueId) { + try { + writeLock(); + if (driversByUniqueId == null) { + driversByUniqueId = new ConcurrentHashMap<>(); + } + driversByUniqueId.remove(driverUniqueId); + } finally { + writeUnlock(); } - driversByUniqueId.put(driver.getUniqueId(), driver); } @Override protected void addNewItem(Driver driver) { super.addNewItem(driver); - putUniqueDriverId(driver); + addByUniqueId(driver); } @Override @@ -50,9 +72,9 @@ public class DriversManager extends ExtendedObjectManager { Driver cachedDriver = getById(driver.getId()); cachedDriver.setName(driver.getName()); if (!driver.getUniqueId().equals(cachedDriver.getUniqueId())) { - driversByUniqueId.remove(cachedDriver.getUniqueId()); + removeByUniqueId(cachedDriver.getUniqueId()); cachedDriver.setUniqueId(driver.getUniqueId()); - putUniqueDriverId(cachedDriver); + addByUniqueId(cachedDriver); } cachedDriver.setAttributes(driver.getAttributes()); } @@ -63,11 +85,16 @@ public class DriversManager extends ExtendedObjectManager { if (cachedDriver != null) { String driverUniqueId = cachedDriver.getUniqueId(); super.removeCachedItem(driverId); - driversByUniqueId.remove(driverUniqueId); + removeByUniqueId(driverUniqueId); } } public Driver getDriverByUniqueId(String uniqueId) { - return driversByUniqueId.get(uniqueId); + try { + readLock(); + return driversByUniqueId.get(uniqueId); + } finally { + readUnlock(); + } } } diff --git a/src/main/java/org/traccar/database/ExtendedObjectManager.java b/src/main/java/org/traccar/database/ExtendedObjectManager.java index ceb85b537..93e5820fb 100644 --- a/src/main/java/org/traccar/database/ExtendedObjectManager.java +++ b/src/main/java/org/traccar/database/ExtendedObjectManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -45,24 +45,45 @@ public abstract class ExtendedObjectManager extends SimpleO } public final Set getGroupItems(long groupId) { - if (!groupItems.containsKey(groupId)) { - groupItems.put(groupId, new HashSet()); + try { + readLock(); + Set result = groupItems.get(groupId); + if (result != null) { + return new HashSet<>(result); + } else { + return new HashSet<>(); + } + } finally { + readUnlock(); } - return groupItems.get(groupId); } public final Set getDeviceItems(long deviceId) { - if (!deviceItems.containsKey(deviceId)) { - deviceItems.put(deviceId, new HashSet()); + try { + readLock(); + Set result = deviceItems.get(deviceId); + if (result != null) { + return new HashSet<>(result); + } else { + return new HashSet<>(); + } + } finally { + readUnlock(); } - return deviceItems.get(deviceId); } public Set getAllDeviceItems(long deviceId) { - if (!deviceItemsWithGroups.containsKey(deviceId)) { - deviceItemsWithGroups.put(deviceId, new HashSet()); + try { + readLock(); + Set result = deviceItemsWithGroups.get(deviceId); + if (result != null) { + return new HashSet<>(result); + } else { + return new HashSet<>(); + } + } finally { + readUnlock(); } - return deviceItemsWithGroups.get(deviceId); } @Override @@ -74,41 +95,48 @@ public abstract class ExtendedObjectManager extends SimpleO public void refreshExtendedPermissions() { if (getDataManager() != null) { try { - Collection databaseGroupPermissions = getDataManager().getPermissions(Group.class, getBaseClass()); - groupItems.clear(); - for (Permission groupPermission : databaseGroupPermissions) { - getGroupItems(groupPermission.getOwnerId()).add(groupPermission.getPropertyId()); - } - Collection databaseDevicePermissions = getDataManager().getPermissions(Device.class, getBaseClass()); + writeLock(); + + groupItems.clear(); deviceItems.clear(); deviceItemsWithGroups.clear(); + for (Permission groupPermission : databaseGroupPermissions) { + groupItems + .computeIfAbsent(groupPermission.getOwnerId(), key -> new HashSet<>()) + .add(groupPermission.getPropertyId()); + } + for (Permission devicePermission : databaseDevicePermissions) { - getDeviceItems(devicePermission.getOwnerId()).add(devicePermission.getPropertyId()); - getAllDeviceItems(devicePermission.getOwnerId()).add(devicePermission.getPropertyId()); + deviceItems + .computeIfAbsent(devicePermission.getOwnerId(), key -> new HashSet<>()) + .add(devicePermission.getPropertyId()); + deviceItemsWithGroups + .computeIfAbsent(devicePermission.getOwnerId(), key -> new HashSet<>()) + .add(devicePermission.getPropertyId()); } for (Device device : Context.getDeviceManager().getAllDevices()) { long groupId = device.getGroupId(); - while (groupId != 0) { - getAllDeviceItems(device.getId()).addAll(getGroupItems(groupId)); + while (groupId > 0) { + deviceItemsWithGroups + .computeIfAbsent(device.getId(), key -> new HashSet<>()) + .addAll(groupItems.getOrDefault(groupId, new HashSet<>())); Group group = Context.getGroupsManager().getById(groupId); - if (group != null) { - groupId = group.getGroupId(); - } else { - groupId = 0; - } + groupId = group != null ? group.getGroupId() : 0; } } } catch (SQLException | ClassNotFoundException error) { LOGGER.warn("Refresh permissions error", error); + } finally { + writeUnlock(); } } } diff --git a/src/main/java/org/traccar/database/GroupsManager.java b/src/main/java/org/traccar/database/GroupsManager.java index d8404c614..81f1968aa 100644 --- a/src/main/java/org/traccar/database/GroupsManager.java +++ b/src/main/java/org/traccar/database/GroupsManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -95,8 +95,7 @@ public class GroupsManager extends BaseObjectManager implements Managable @Override public Set getManagedItems(long userId) { - Set result = new HashSet<>(); - result.addAll(getUserItems(userId)); + Set result = getUserItems(userId); for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { result.addAll(getUserItems(managedUserId)); } diff --git a/src/main/java/org/traccar/database/SimpleObjectManager.java b/src/main/java/org/traccar/database/SimpleObjectManager.java index 15dda4520..eb8284d4e 100644 --- a/src/main/java/org/traccar/database/SimpleObjectManager.java +++ b/src/main/java/org/traccar/database/SimpleObjectManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -42,16 +42,22 @@ public abstract class SimpleObjectManager extends BaseObjec @Override public final Set getUserItems(long userId) { - if (!userItems.containsKey(userId)) { - userItems.put(userId, new HashSet()); + try { + readLock(); + Set result = userItems.get(userId); + if (result != null) { + return new HashSet<>(result); + } else { + return new HashSet<>(); + } + } finally { + readUnlock(); } - return userItems.get(userId); } @Override public Set getManagedItems(long userId) { - Set result = new HashSet<>(); - result.addAll(getUserItems(userId)); + Set result = getUserItems(userId); for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { result.addAll(getUserItems(managedUserId)); } @@ -71,16 +77,16 @@ public abstract class SimpleObjectManager extends BaseObjec public final void refreshUserItems() { if (getDataManager() != null) { try { - if (userItems != null) { - userItems.clear(); - } else { - userItems = new ConcurrentHashMap<>(); - } + writeLock(); + userItems = new ConcurrentHashMap<>(); for (Permission permission : getDataManager().getPermissions(User.class, getBaseClass())) { - getUserItems(permission.getOwnerId()).add(permission.getPropertyId()); + Set items = userItems.computeIfAbsent(permission.getOwnerId(), key -> new HashSet<>()); + items.add(permission.getPropertyId()); } } catch (SQLException | ClassNotFoundException error) { LOGGER.warn("Error getting permissions", error); + } finally { + writeUnlock(); } } } diff --git a/src/main/java/org/traccar/database/UsersManager.java b/src/main/java/org/traccar/database/UsersManager.java index 576a9e6c7..b741a85b6 100644 --- a/src/main/java/org/traccar/database/UsersManager.java +++ b/src/main/java/org/traccar/database/UsersManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,6 @@ */ package org.traccar.database; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -73,8 +72,7 @@ public class UsersManager extends SimpleObjectManager { @Override public Set getManagedItems(long userId) { - Set result = new HashSet<>(); - result.addAll(getUserItems(userId)); + Set result = getUserItems(userId); result.add(userId); return result; } -- cgit v1.2.3 From 8d6e45331cb4ba86faaabfe7d1f9e7ccfd6e824d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 22 Feb 2020 16:59:43 -0800 Subject: Support health monitoring --- setup/default.xml | 1 + setup/traccar.service | 3 + src/main/java/org/traccar/Main.java | 59 ++++++++------ .../java/org/traccar/api/HealthCheckService.java | 90 ++++++++++++++++++++++ 4 files changed, 130 insertions(+), 23 deletions(-) create mode 100644 src/main/java/org/traccar/api/HealthCheckService.java diff --git a/setup/default.xml b/setup/default.xml index 1d82ad926..561b57a57 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -14,6 +14,7 @@ 8082 ./web max-age=3600,public + true false google diff --git a/setup/traccar.service b/setup/traccar.service index fe746dda8..6ae24ab8a 100644 --- a/setup/traccar.service +++ b/setup/traccar.service @@ -8,6 +8,9 @@ WorkingDirectory=/opt/traccar ExecStart=/opt/traccar/jre/bin/java -jar tracker-server.jar conf/traccar.xml SyslogIdentifier=traccar SuccessExitStatus=143 +WatchdogSec=100 +Restart=on-failure +RestartSec=10 [Install] WantedBy=multi-user.target diff --git a/src/main/java/org/traccar/Main.java b/src/main/java/org/traccar/Main.java index 6ebd1d399..f5690b26d 100644 --- a/src/main/java/org/traccar/Main.java +++ b/src/main/java/org/traccar/Main.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2020 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. @@ -19,6 +19,7 @@ import com.google.inject.Guice; import com.google.inject.Injector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.traccar.api.HealthCheckService; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; @@ -105,6 +106,27 @@ public final class Main { } } + private static void scheduleHealthCheck() { + HealthCheckService service = new HealthCheckService(); + if (service.isEnabled()) { + new Timer().scheduleAtFixedRate( + service.createTask(), service.getPeriod(), service.getPeriod()); + } + } + + private static void scheduleDatabaseCleanup() { + new Timer().scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + try { + Context.getDataManager().clearHistory(); + } catch (SQLException error) { + LOGGER.warn("Clear history error", error); + } + } + }, 0, CLEAN_PERIOD); + } + public static void run(String configFile) { try { Context.init(configFile); @@ -118,35 +140,26 @@ public final class Main { Context.getWebServer().start(); } - new Timer().scheduleAtFixedRate(new TimerTask() { + new Timer().schedule(new TimerTask() { @Override public void run() { - try { - Context.getDataManager().clearHistory(); - } catch (SQLException error) { - LOGGER.warn("Clear history error", error); - } + Context.getWebServer().stop(); } - }, 0, CLEAN_PERIOD); + }, 10 * 60 * 1000); - Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - LOGGER.error("Thread exception", e); - } - }); + scheduleHealthCheck(); + scheduleDatabaseCleanup(); - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - LOGGER.info("Shutting down server..."); + Thread.setDefaultUncaughtExceptionHandler((t, e) -> LOGGER.error("Thread exception", e)); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + LOGGER.info("Shutting down server..."); - if (Context.getWebServer() != null) { - Context.getWebServer().stop(); - } - Context.getServerManager().stop(); + if (Context.getWebServer() != null) { + Context.getWebServer().stop(); } - }); + Context.getServerManager().stop(); + })); } catch (Exception e) { LOGGER.error("Main method error", e); throw new RuntimeException(e); diff --git a/src/main/java/org/traccar/api/HealthCheckService.java b/src/main/java/org/traccar/api/HealthCheckService.java new file mode 100644 index 000000000..cd2856dfa --- /dev/null +++ b/src/main/java/org/traccar/api/HealthCheckService.java @@ -0,0 +1,90 @@ +/* + * Copyright 2020 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.api; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; + +import java.util.TimerTask; + +public class HealthCheckService { + + private static final Logger LOGGER = LoggerFactory.getLogger(HealthCheckService.class); + + private SystemD systemD; + + private boolean enabled; + private long period; + + public HealthCheckService() { + if (Context.getConfig().getBoolean("web.healthCheck") + && System.getProperty("os.name").toLowerCase().startsWith("linux")) { + try { + systemD = Native.load("systemd", SystemD.class); + String watchdogTimer = System.getenv("WATCHDOG_USEC"); + if (watchdogTimer != null && !watchdogTimer.isEmpty()) { + period = Long.parseLong(watchdogTimer) / 1000 * 4 / 5; + } + if (period > 0) { + LOGGER.info("Health check enabled with period {}", period); + enabled = true; + } + } catch (UnsatisfiedLinkError e) { + LOGGER.warn("No systemd support", e); + } + } + } + + public boolean isEnabled() { + return enabled; + } + + public long getPeriod() { + return period; + } + + private String getUrl() { + String address = Context.getConfig().getString("web.address", "localhost"); + int port = Context.getConfig().getInteger("web.port", 8082); + return "http://" + address + ":" + port + "/api/server"; + } + + public TimerTask createTask() { + return new TimerTask() { + @Override + public void run() { + LOGGER.debug("Health check running"); + int status = Context.getClient().target(getUrl()).request().get().getStatus(); + if (status == 200) { + int result = systemD.sd_notify(0, "WATCHDOG=1"); + if (result < 0) { + LOGGER.warn("Health check notify error {}", result); + } + } else { + LOGGER.warn("Health check failed with status {}", status); + } + } + }; + } + + interface SystemD extends Library { + int sd_notify(int unset_environment, String state); + } + +} -- cgit v1.2.3 From 43abeeb1dad9e15681d87b299752d057914ae29e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 22 Feb 2020 17:43:09 -0800 Subject: Fix style check --- gradle/checkstyle.xml | 4 ++++ src/main/java/org/traccar/api/HealthCheckService.java | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/gradle/checkstyle.xml b/gradle/checkstyle.xml index 72950c7bd..e4df54d8c 100644 --- a/gradle/checkstyle.xml +++ b/gradle/checkstyle.xml @@ -5,6 +5,8 @@ + + @@ -51,6 +53,8 @@ + + diff --git a/src/main/java/org/traccar/api/HealthCheckService.java b/src/main/java/org/traccar/api/HealthCheckService.java index cd2856dfa..1e8f0d731 100644 --- a/src/main/java/org/traccar/api/HealthCheckService.java +++ b/src/main/java/org/traccar/api/HealthCheckService.java @@ -84,7 +84,8 @@ public class HealthCheckService { } interface SystemD extends Library { - int sd_notify(int unset_environment, String state); + @SuppressWarnings("checkstyle:MethodName") + int sd_notify(@SuppressWarnings("checkstyle:ParameterName") int unset_environment, String state); } } -- cgit v1.2.3 From b23b1efe6b3dba788f3acb87b403522097114208 Mon Sep 17 00:00:00 2001 From: alexthefifth <10274240+alexthefifth@users.noreply.github.com> Date: Sun, 23 Feb 2020 15:08:41 -0500 Subject: Do not require password (default when programming MT600 via USB) --- src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java index 7ad99b37e..3ce6438f8 100644 --- a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java @@ -38,7 +38,7 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_HEADER = new PatternBuilder() .number("#(d+)") // imei .expression("#[^#]*") // user - .number("#d+") // password + .number("#d*") // password .groupBegin() .number("#([01])") // door .number("#(d+)") // fuel voltage -- cgit v1.2.3 From 7db2926c38edafb4cbd9b2cda1a98b5567836bc1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 23 Feb 2020 17:34:08 -0800 Subject: Remove debugging code --- src/main/java/org/traccar/Main.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/java/org/traccar/Main.java b/src/main/java/org/traccar/Main.java index f5690b26d..47d6e91df 100644 --- a/src/main/java/org/traccar/Main.java +++ b/src/main/java/org/traccar/Main.java @@ -140,13 +140,6 @@ public final class Main { Context.getWebServer().start(); } - new Timer().schedule(new TimerTask() { - @Override - public void run() { - Context.getWebServer().stop(); - } - }, 10 * 60 * 1000); - scheduleHealthCheck(); scheduleDatabaseCleanup(); -- cgit v1.2.3 From 1049b01a22e28acb69ea530de824608b72c8222c Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Tue, 25 Feb 2020 18:27:26 -0500 Subject: Changes after review --- src/main/java/org/traccar/MainModule.java | 2 +- src/main/java/org/traccar/WebDataHandler.java | 142 +++++++++++++------------- 2 files changed, 74 insertions(+), 70 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 24448ef51..1d5508f5a 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -378,7 +378,7 @@ public class MainModule extends AbstractModule { @Singleton @Provides - public static Timer provideGlobalTimer() { + public static Timer provideTimer() { return GlobalTimer.getTimer(); } diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java index 58b9ca73b..39e54616b 100644 --- a/src/main/java/org/traccar/WebDataHandler.java +++ b/src/main/java/org/traccar/WebDataHandler.java @@ -53,11 +53,11 @@ import java.util.concurrent.atomic.AtomicInteger; @ChannelHandler.Sharable public class WebDataHandler extends BaseDataHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(WebDataHandler.class); + private static final String KEY_POSITION = "position"; private static final String KEY_DEVICE = "device"; - private static final Logger LOGGER = LoggerFactory.getLogger(WebDataHandler.class); - private final IdentityManager identityManager; private final ObjectMapper objectMapper; private final Client client; @@ -179,94 +179,98 @@ public class WebDataHandler extends BaseDataHandler { return request; } - @Override - protected Position handlePosition(Position position) { + class AsyncRequestAndCallback implements InvocationCallback, TimerTask { - class AsyncRequestAndCallback implements InvocationCallback { + private int retries = 0; + private Map payload; + private Invocation.Builder requestBuilder; - private int retries = 0; - private Map payload; - private Invocation.Builder requestBuilder; + AsyncRequestAndCallback(Position position) { - AsyncRequestAndCallback(Position position) { - - String formattedUrl; - try { - formattedUrl = json ? url : formatRequest(position); - } catch (UnsupportedEncodingException | JsonProcessingException e) { - throw new RuntimeException("Forwarding formatting error", e); - } + String formattedUrl; + try { + formattedUrl = json ? url : formatRequest(position); + } catch (UnsupportedEncodingException | JsonProcessingException e) { + throw new RuntimeException("Forwarding formatting error", e); + } - requestBuilder = client.target(formattedUrl).request(); - if (header != null && !header.isEmpty()) { - for (String line: header.split("\\r?\\n")) { - String[] values = line.split(":", 2); - requestBuilder.header(values[0].trim(), values[1].trim()); - } + requestBuilder = client.target(formattedUrl).request(); + if (header != null && !header.isEmpty()) { + for (String line: header.split("\\r?\\n")) { + String[] values = line.split(":", 2); + requestBuilder.header(values[0].trim(), values[1].trim()); } + } - if (json) { - payload = prepareJsonPayload(position); - } + if (json) { + payload = prepareJsonPayload(position); + } - deliveryPending.incrementAndGet(); + deliveryPending.incrementAndGet(); + } - send(); + private void send() { + if (json) { + requestBuilder.async().post(Entity.json(payload), this); + } else { + requestBuilder.async().get(this); } + } - private void send() { - if (json) { - requestBuilder.async().post(Entity.json(payload), this); - } else { - requestBuilder.async().get(this); + private void retry() { + boolean scheduled = false; + try { + if (retryEnabled && deliveryPending.get() <= retryLimit && retries < retryCount) { + schedule(); + scheduled = true; } + } finally { + int pending = scheduled ? deliveryPending.get() : deliveryPending.decrementAndGet(); + LOGGER.warn("Position forwarding failed: " + pending + " pending"); } + } - private void retry() { - boolean ok = false; - try { - if (retryEnabled && deliveryPending.get() <= retryLimit && retries < retryCount) { - Main.getInjector().getInstance(Timer.class).newTimeout(new TimerTask() { - @Override - public void run(Timeout timeout) { - boolean ok = false; - try { - if (!timeout.isCancelled()) { - send(); - ok = true; - } - } finally { - if (!ok) { - deliveryPending.decrementAndGet(); - } - } - } - }, retryDelay * (int) Math.pow(2, retries++), TimeUnit.MILLISECONDS); - ok = true; - } - } finally { - int pending = ok ? deliveryPending.get() : deliveryPending.decrementAndGet(); - LOGGER.warn("Position forwarding failed: " + pending + " pending"); - } + private void schedule() { + Main.getInjector().getInstance(Timer.class).newTimeout( + this, retryDelay * (int) Math.pow(2, retries++), TimeUnit.MILLISECONDS); + } + + @Override + public void completed(Response response) { + if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) { + deliveryPending.decrementAndGet(); + } else { + retry(); } + } + + @Override + public void failed(Throwable throwable) { + retry(); + } - @Override - public void completed(Response response) { - if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) { + @Override + public void run(Timeout timeout) { + boolean sent = false; + try { + if (!timeout.isCancelled()) { + send(); + sent = true; + } + } finally { + if (!sent) { deliveryPending.decrementAndGet(); - } else { - retry(); } } + } - @Override - public void failed(Throwable throwable) { - retry(); - } + } - } + @Override + protected Position handlePosition(Position position) { - new AsyncRequestAndCallback(position); + AsyncRequestAndCallback request = new AsyncRequestAndCallback(position); + request.send(); return position; } -- cgit v1.2.3 From 886a1ac0550c5aecb13222668f4ca35758ec92d1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 25 Feb 2020 21:40:33 -0800 Subject: Decode ignition value --- src/main/java/org/traccar/protocol/EskyProtocolDecoder.java | 6 +++++- src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java b/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java index d9de110f4..f0ae0bc91 100644 --- a/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java @@ -21,6 +21,7 @@ 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.Parser; import org.traccar.helper.PatternBuilder; import org.traccar.helper.UnitsConverter; @@ -88,7 +89,10 @@ public class EskyProtocolDecoder extends BaseProtocolDecoder { position.setCourse(parser.nextDouble()); if (parser.hasNext(3)) { - position.set(Position.KEY_INPUT, parser.nextHexInt()); + int input = parser.nextHexInt(); + position.set(Position.KEY_IGNITION, !BitUtil.check(input, 0)); + position.set(Position.PREFIX_IN + 1, !BitUtil.check(input, 1)); + position.set(Position.PREFIX_IN + 2, !BitUtil.check(input, 2)); position.set(Position.KEY_EVENT, parser.nextInt()); position.set(Position.KEY_ODOMETER, parser.nextInt()); } diff --git a/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java index da7df0ab2..4db80c7ce 100644 --- a/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java @@ -2,6 +2,7 @@ package org.traccar.protocol; import org.junit.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Position; public class EskyProtocolDecoderTest extends ProtocolTest { @@ -10,6 +11,10 @@ public class EskyProtocolDecoderTest extends ProtocolTest { EskyProtocolDecoder decoder = new EskyProtocolDecoder(null); + verifyAttribute(decoder, text( + "ET;0;860337031078319;R;6+190317162511+41.32536+19.83144+0.14+0+0x0+0+18460312+0+1233+192"), + Position.KEY_IGNITION, true); + verifyPosition(decoder, text( "EO;0;861311006461908;R;6;180420104751;2.97896;101.65091;0.75;320;3398;1;|")); -- cgit v1.2.3 From e4f6e74e57ab743b65d49ae00f6624a20ca0291e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 25 Feb 2020 22:26:18 -0800 Subject: Encode LDAP user names --- .../java/org/traccar/database/LdapProvider.java | 36 ++++++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/database/LdapProvider.java b/src/main/java/org/traccar/database/LdapProvider.java index d8b5c9f52..447904b35 100644 --- a/src/main/java/org/traccar/database/LdapProvider.java +++ b/src/main/java/org/traccar/database/LdapProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 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. @@ -81,7 +81,7 @@ public class LdapProvider { if (this.adminFilter != null) { try { InitialDirContext context = initContext(); - String searchString = adminFilter.replace(":login", accountName); + String searchString = adminFilter.replace(":login", encodeForLdap(accountName)); SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); NamingEnumeration results = context.search(searchBase, searchString, searchControls); @@ -107,7 +107,7 @@ public class LdapProvider { private SearchResult lookupUser(String accountName) throws NamingException { InitialDirContext context = initContext(); - String searchString = searchFilter.replace(":login", accountName); + String searchString = searchFilter.replace(":login", encodeForLdap(accountName)); SearchControls searchControls = new SearchControls(); String[] attributeFilter = {idAttribute, nameAttribute, mailAttribute}; @@ -176,4 +176,34 @@ public class LdapProvider { return false; } + public String encodeForLdap(String input) { + if( input == null ) { + return null; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + switch (c) { + case '\\': + sb.append("\\5c"); + break; + case '*': + sb.append("\\2a"); + break; + case '(': + sb.append("\\28"); + break; + case ')': + sb.append("\\29"); + break; + case '\0': + sb.append("\\00"); + break; + default: + sb.append(c); + } + } + return sb.toString(); + } + } -- cgit v1.2.3 From 0dcb514f3a0cb66e8c3e4e7b60c9374b2579f7d2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 25 Feb 2020 22:32:54 -0800 Subject: Fix style issue --- src/main/java/org/traccar/database/LdapProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/database/LdapProvider.java b/src/main/java/org/traccar/database/LdapProvider.java index 447904b35..a8220ea8e 100644 --- a/src/main/java/org/traccar/database/LdapProvider.java +++ b/src/main/java/org/traccar/database/LdapProvider.java @@ -177,7 +177,7 @@ public class LdapProvider { } public String encodeForLdap(String input) { - if( input == null ) { + if (input == null) { return null; } StringBuilder sb = new StringBuilder(); -- cgit v1.2.3 From a48c68d4b5fb522081c9182713a4088a66317964 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 28 Feb 2020 09:12:30 -0800 Subject: Fix ITS status decoding --- src/main/java/org/traccar/protocol/ItsProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java b/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java index e8d77f1a8..6a107d67d 100644 --- a/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java @@ -51,7 +51,7 @@ public class ItsProtocolDecoder extends BaseProtocolDecoder { .groupEnd() .number("(d{15}),") // imei .groupBegin() - .expression("(..),") // status + .expression("([^,]{2}),") // status .or() .expression("[^,]*,") // vehicle registration .number("([01]),").optional() // valid -- cgit v1.2.3 From 1ab53d1f4911e349370542b23a5fa3fe69be7dcc Mon Sep 17 00:00:00 2001 From: Andreas Date: Sun, 1 Mar 2020 23:18:44 +0100 Subject: add support for pushover.net --- .../traccar/notification/NotificatorManager.java | 4 + .../traccar/notificators/NotificatorPushover.java | 89 ++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/main/java/org/traccar/notificators/NotificatorPushover.java diff --git a/src/main/java/org/traccar/notification/NotificatorManager.java b/src/main/java/org/traccar/notification/NotificatorManager.java index 191748379..c5f1ad8a0 100644 --- a/src/main/java/org/traccar/notification/NotificatorManager.java +++ b/src/main/java/org/traccar/notification/NotificatorManager.java @@ -32,6 +32,7 @@ import org.traccar.notificators.Notificator; import org.traccar.notificators.NotificatorSms; import org.traccar.notificators.NotificatorWeb; import org.traccar.notificators.NotificatorTelegram; +import org.traccar.notificators.NotificatorPushover; public final class NotificatorManager { @@ -61,6 +62,9 @@ public final class NotificatorManager { case "telegram": defaultNotificator = NotificatorTelegram.class.getCanonicalName(); break; + case "pushover": + defaultNotificator = NotificatorPushover.class.getCanonicalName(); + break; default: break; } diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java new file mode 100644 index 000000000..21da1f8d5 --- /dev/null +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -0,0 +1,89 @@ +/* + * 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.notificators; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.Event; +import org.traccar.model.Position; +import org.traccar.notification.NotificationFormatter; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.InvocationCallback; + +public class NotificatorPushover extends Notificator { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorPushover.class); + + private String url; + private String token; + private String user; + private String device; + private String title; + + public static class Message { + @JsonProperty("token") + private String token; + @JsonProperty("user") + private String user; + @JsonProperty("device") + private String device; + @JsonProperty("title") + private String title; + @JsonProperty("message") + private String message; + } + + public NotificatorPushover() { + url = "https://api.pushover.net/1/messages.json"; + // see https://pushover.net/api + token = Context.getConfig().getString("notificator.pushover.token"); // (required) token from pushover.net + user = Context.getConfig().getString("notificator.pushover.user"); // (required) user from pushover.net + device = Context.getConfig().getString("notificator.pushover.device",""); // optional: your user's device name to send the message directly to that device, rather than all of the user's devices (multiple devices may be separated by a comma) + title = Context.getConfig().getString("notificator.pushover.title",""); // optional: your message's title, otherwise your app's name is used + } + + @Override + public void sendSync(long userId, Event event, Position position) { + + Message message = new Message(); + message.token = token; + message.user = user; + message.device = device; + message.title = title; + message.message = NotificationFormatter.formatShortMessage(userId, event, position); + + Context.getClient().target(url).request() + .async().post(Entity.json(message), new InvocationCallback() { + @Override + public void completed(Object o) { + } + + @Override + public void failed(Throwable throwable) { + LOGGER.warn("Pushover API error", throwable); + } + }); + } + + @Override + public void sendAsync(long userId, Event event, Position position) { + sendSync(userId, event, position); + } + +} -- cgit v1.2.3 From 39a2742121de3e016655e9fc5d5ba886e1ab900b Mon Sep 17 00:00:00 2001 From: Andreas Date: Sun, 1 Mar 2020 23:36:54 +0100 Subject: comment too long --- src/main/java/org/traccar/notificators/NotificatorPushover.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index 21da1f8d5..29455b1a6 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -54,7 +54,8 @@ public class NotificatorPushover extends Notificator { // see https://pushover.net/api token = Context.getConfig().getString("notificator.pushover.token"); // (required) token from pushover.net user = Context.getConfig().getString("notificator.pushover.user"); // (required) user from pushover.net - device = Context.getConfig().getString("notificator.pushover.device",""); // optional: your user's device name to send the message directly to that device, rather than all of the user's devices (multiple devices may be separated by a comma) + device = Context.getConfig().getString("notificator.pushover.device",""); // optional: your user's device name to send the message directly + // to that device, rather than all of the user's devices (multiple devices may be separated by a comma) title = Context.getConfig().getString("notificator.pushover.title",""); // optional: your message's title, otherwise your app's name is used } -- cgit v1.2.3 From 4a7a3b59c39bcfe9a6d7ed11b27074d7c1f6b418 Mon Sep 17 00:00:00 2001 From: Andreas Date: Sun, 1 Mar 2020 23:44:23 +0100 Subject: comment too long --- src/main/java/org/traccar/notificators/NotificatorPushover.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index 29455b1a6..734e38eb9 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -54,9 +54,11 @@ public class NotificatorPushover extends Notificator { // see https://pushover.net/api token = Context.getConfig().getString("notificator.pushover.token"); // (required) token from pushover.net user = Context.getConfig().getString("notificator.pushover.user"); // (required) user from pushover.net - device = Context.getConfig().getString("notificator.pushover.device",""); // optional: your user's device name to send the message directly + device = Context.getConfig().getString("notificator.pushover.device",""); // optional: + // your user's device name to send the message directly // to that device, rather than all of the user's devices (multiple devices may be separated by a comma) - title = Context.getConfig().getString("notificator.pushover.title",""); // optional: your message's title, otherwise your app's name is used + title = Context.getConfig().getString("notificator.pushover.title",""); // optional: your message's title, + // otherwise your app's name is used } @Override -- cgit v1.2.3 From 535b0ffa9a3e435cd58d4f7ade9a4d8c6eb03623 Mon Sep 17 00:00:00 2001 From: Andreas Date: Sun, 1 Mar 2020 23:47:33 +0100 Subject: add whitespace --- src/main/java/org/traccar/notificators/NotificatorPushover.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index 734e38eb9..ff992ec8d 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -54,10 +54,10 @@ public class NotificatorPushover extends Notificator { // see https://pushover.net/api token = Context.getConfig().getString("notificator.pushover.token"); // (required) token from pushover.net user = Context.getConfig().getString("notificator.pushover.user"); // (required) user from pushover.net - device = Context.getConfig().getString("notificator.pushover.device",""); // optional: + device = Context.getConfig().getString("notificator.pushover.device", ""); // optional: // your user's device name to send the message directly // to that device, rather than all of the user's devices (multiple devices may be separated by a comma) - title = Context.getConfig().getString("notificator.pushover.title",""); // optional: your message's title, + title = Context.getConfig().getString("notificator.pushover.title", ""); // optional: your message's title, // otherwise your app's name is used } -- cgit v1.2.3 From 96d7a6c1f8b2563c3b3fb3d4a8737e8c2d606f6e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 4 Mar 2020 00:07:10 -0800 Subject: Support TopFlyTech variation --- src/main/java/org/traccar/protocol/T800xProtocolDecoder.java | 11 ++++++----- .../java/org/traccar/protocol/T800xProtocolDecoderTest.java | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java index 9b146ec90..3331ebb71 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2020 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. @@ -177,8 +177,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { } private Position decodePosition( - Channel channel, DeviceSession deviceSession, - ByteBuf buf, int type, int index, ByteBuf imei) { + Channel channel, DeviceSession deviceSession, ByteBuf buf, int type, int index, ByteBuf imei) { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); @@ -214,8 +213,10 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_OUT + (i + 1), BitUtil.check(io, 7 + i)); } - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); + if (header != 0x2626) { + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); + } } diff --git a/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java index 28b3fc5c6..48c535c96 100644 --- a/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class T800xProtocolDecoderTest extends ProtocolTest { T800xProtocolDecoder decoder = new T800xProtocolDecoder(null); + verifyPosition(decoder, binary( + "262602005308090865284040309670000f000f0f0000005a47c000050100000020000000008bfd0020022505185300004041dcc9d6c243b3c6410000012712400000000009e2ffffffffffffffffffffffff09")); + verifyPosition(decoder, binary( "2727040049001b0866425039645728c916190604005240000000007739d2c25b681f420000000080000081000020174105000005458216001e000000f01e00001e30d0000000000000")); -- cgit v1.2.3 From 455f96fb074cb02825c8303d0aa8eff0a848e9fd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 4 Mar 2020 00:25:05 -0800 Subject: Decode GSM signal --- .../traccar/protocol/SolarPoweredProtocolDecoder.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java b/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java index eae37386a..6fe54b0b0 100644 --- a/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2020 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. @@ -77,10 +77,24 @@ public class SolarPoweredProtocolDecoder extends BaseProtocolDecoder { position.setLongitude(-position.getLongitude()); } position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - position.set(Position.KEY_DEVICE_TEMP, (int) buf.readByte()); + int temperature = buf.readUnsignedByte(); + if (BitUtil.check(temperature, 7)) { + position.set(Position.KEY_DEVICE_TEMP, -BitUtil.to(temperature, 7)); + } else { + position.set(Position.KEY_DEVICE_TEMP, BitUtil.to(temperature, 7)); + } position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.02); position.setCourse(buf.readUnsignedByte()); break; + case 0x83: + buf.readUnsignedInt(); // uptime + buf.readUnsignedInt(); // gps count + buf.readUnsignedInt(); // gsm count + buf.readUnsignedByte(); // positioning time + buf.readUnsignedByte(); // registration time + buf.readUnsignedByte(); // connection time + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + break; default: buf.skipBytes(length); break; -- cgit v1.2.3 From 83148e8750ba9689b4dc53f586e0ce1e23cf2032 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 4 Mar 2020 00:32:44 -0800 Subject: Convert sensor data --- src/main/java/org/traccar/protocol/BceProtocolDecoder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java index 54136382c..1b354c861 100644 --- a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java @@ -217,9 +217,9 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedShortLE(); } if (BitUtil.check(mask, 6)) { - position.set("maxAcceleration", buf.readUnsignedByte()); - position.set("maxBraking", buf.readUnsignedByte()); - position.set("maxCornering", buf.readUnsignedByte()); + position.set("maxAcceleration", buf.readUnsignedByte() * 0.02); + position.set("maxBraking", buf.readUnsignedByte() * 0.02); + position.set("maxCornering", buf.readUnsignedByte() * 0.02); } if (BitUtil.check(mask, 7)) { buf.skipBytes(16); -- cgit v1.2.3 From dd23d3becaf50ad4cdaf0064712f1f104e1c5967 Mon Sep 17 00:00:00 2001 From: Vitaliy Gergel Date: Wed, 4 Mar 2020 16:38:50 +0200 Subject: Allowing custom content type header in location forward --- src/main/java/org/traccar/WebDataHandler.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java index 39e54616b..c8bb9b461 100644 --- a/src/main/java/org/traccar/WebDataHandler.java +++ b/src/main/java/org/traccar/WebDataHandler.java @@ -33,6 +33,8 @@ import org.traccar.model.Position; import org.traccar.model.Group; import javax.inject.Inject; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.client.Client; import javax.ws.rs.client.Entity; @@ -184,6 +186,7 @@ public class WebDataHandler extends BaseDataHandler { private int retries = 0; private Map payload; private Invocation.Builder requestBuilder; + private MediaType mediaType = MediaType.APPLICATION_JSON_TYPE; AsyncRequestAndCallback(Position position) { @@ -198,7 +201,12 @@ public class WebDataHandler extends BaseDataHandler { if (header != null && !header.isEmpty()) { for (String line: header.split("\\r?\\n")) { String[] values = line.split(":", 2); - requestBuilder.header(values[0].trim(), values[1].trim()); + String headerName = values[0].trim(); + String headerValue = values[1].trim(); + requestBuilder.header(headerName, headerValue); + if (headerName.equals(HttpHeaders.CONTENT_TYPE)) { + mediaType = MediaType.valueOf(headerValue); + } } } @@ -211,7 +219,11 @@ public class WebDataHandler extends BaseDataHandler { private void send() { if (json) { - requestBuilder.async().post(Entity.json(payload), this); + try { + requestBuilder.async().post(Entity.entity(objectMapper.writeValueAsString(payload), mediaType), this); + } catch (JsonProcessingException e) { + throw new RuntimeException("Failed to serialize payload to json: " + payload); + } } else { requestBuilder.async().get(this); } -- cgit v1.2.3 From e7c04c8dfaa67e5bef2d3b9c5ba8924e85045ffc Mon Sep 17 00:00:00 2001 From: Vitaliy Gergel Date: Wed, 4 Mar 2020 21:18:14 +0200 Subject: Fix code review comments and repace url variables for post request as well --- src/main/java/org/traccar/WebDataHandler.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java index c8bb9b461..858b00aad 100644 --- a/src/main/java/org/traccar/WebDataHandler.java +++ b/src/main/java/org/traccar/WebDataHandler.java @@ -192,7 +192,7 @@ public class WebDataHandler extends BaseDataHandler { String formattedUrl; try { - formattedUrl = json ? url : formatRequest(position); + formattedUrl = formatRequest(position); } catch (UnsupportedEncodingException | JsonProcessingException e) { throw new RuntimeException("Forwarding formatting error", e); } @@ -203,9 +203,10 @@ public class WebDataHandler extends BaseDataHandler { String[] values = line.split(":", 2); String headerName = values[0].trim(); String headerValue = values[1].trim(); - requestBuilder.header(headerName, headerValue); if (headerName.equals(HttpHeaders.CONTENT_TYPE)) { mediaType = MediaType.valueOf(headerValue); + } else { + requestBuilder.header(headerName, headerValue); } } } @@ -220,9 +221,10 @@ public class WebDataHandler extends BaseDataHandler { private void send() { if (json) { try { - requestBuilder.async().post(Entity.entity(objectMapper.writeValueAsString(payload), mediaType), this); + Entity entity = Entity.entity(objectMapper.writeValueAsString(payload), mediaType); + requestBuilder.async().post(entity, this); } catch (JsonProcessingException e) { - throw new RuntimeException("Failed to serialize payload to json: " + payload); + throw new RuntimeException("Failed to serialize location to json", e); } } else { requestBuilder.async().get(this); -- cgit v1.2.3 From 0270f5b639166b385ac779c0d2caa41d7c408771 Mon Sep 17 00:00:00 2001 From: Vitaliy Gergel Date: Wed, 4 Mar 2020 21:54:55 +0200 Subject: Adding property to enable URL parameter in json mode --- src/main/java/org/traccar/WebDataHandler.java | 4 +++- src/main/java/org/traccar/config/Keys.java | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java index 858b00aad..1af1af48a 100644 --- a/src/main/java/org/traccar/WebDataHandler.java +++ b/src/main/java/org/traccar/WebDataHandler.java @@ -67,6 +67,7 @@ public class WebDataHandler extends BaseDataHandler { private final String url; private final String header; private final boolean json; + private final boolean jsonUrlVariables; private final boolean retryEnabled; private final int retryDelay; @@ -85,6 +86,7 @@ public class WebDataHandler extends BaseDataHandler { this.url = config.getString(Keys.FORWARD_URL); this.header = config.getString(Keys.FORWARD_HEADER); this.json = config.getBoolean(Keys.FORWARD_JSON); + this.jsonUrlVariables = config.getBoolean(Keys.FORWARD_JSON_URL_VARIABLES); this.retryEnabled = config.getBoolean(Keys.FORWARD_RETRY_ENABLE); this.retryDelay = config.getInteger(Keys.FORWARD_RETRY_DELAY, 100); @@ -192,7 +194,7 @@ public class WebDataHandler extends BaseDataHandler { String formattedUrl; try { - formattedUrl = formatRequest(position); + formattedUrl = (json && !jsonUrlVariables) ? url : formatRequest(position); } catch (UnsupportedEncodingException | JsonProcessingException e) { throw new RuntimeException("Forwarding formatting error", e); } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index d88b36d28..a5b7b780c 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -100,6 +100,13 @@ public final class Keys { public static final ConfigKey FORWARD_JSON = new ConfigKey( "forward.json", Boolean.class); + /** + * Boolean value to enable URL parameters in json mode. For example, {uniqueId} for device identifier, + * {latitude} and {longitude} for coordinates. + */ + public static final ConfigKey FORWARD_JSON_URL_VARIABLES = new ConfigKey( + "forward.json.url.variables", Boolean.class); + /** * Position forwarding retrying enable. When enabled, additional attempts are made to deliver positions. If initial * delivery fails, because of an unreachable server or an HTTP response different from '2xx', the software waits -- cgit v1.2.3 From e39eaf2e9878fe8e575b525dd2ca747e3f5342fe Mon Sep 17 00:00:00 2001 From: Andreas Date: Wed, 4 Mar 2020 21:40:43 +0100 Subject: add Pushover attrs in web interface --- .../traccar/notificators/NotificatorPushover.java | 95 +++++++++++++++++++--- traccar-web | 2 +- 2 files changed, 85 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index ff992ec8d..ae48bd46a 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -23,6 +23,10 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.notification.NotificationFormatter; +import org.traccar.model.User; +import org.traccar.notification.PropertiesProvider; +import java.util.Properties; + import javax.ws.rs.client.Entity; import javax.ws.rs.client.InvocationCallback; @@ -30,9 +34,36 @@ public class NotificatorPushover extends Notificator { private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorPushover.class); - private String url; + private static Properties getProperties(PropertiesProvider provider) { + Properties properties = new Properties(); + // (required) token from pushover.net + String token = provider.getString("notificator.pushover.token"); + if (token != null) { + properties.put("notificator.pushover.token", token); + } + // (required) user from pushover.net + String user = provider.getString("notificator.pushover.user"); + if (user != null) { + properties.put("notificator.pushover.user", user); + } + // optional: your user's device name to send the message directly + // to that device, rather than all of the user's devices (multiple devices may be separated by a comma) + String device = provider.getString("notificator.pushover.device"); + if (device != null) { + properties.put("notificator.pushover.device", device); + } + // optional: your message's title, otherwise your app's name is used + String title = provider.getString("notificator.pushover.title"); + if (title != null) { + properties.put("notificator.pushover.title", title); + } + return properties; + } + + + private final String url; private String token; - private String user; + private String puser; private String device; private String title; @@ -50,23 +81,65 @@ public class NotificatorPushover extends Notificator { } public NotificatorPushover() { - url = "https://api.pushover.net/1/messages.json"; // see https://pushover.net/api - token = Context.getConfig().getString("notificator.pushover.token"); // (required) token from pushover.net - user = Context.getConfig().getString("notificator.pushover.user"); // (required) user from pushover.net - device = Context.getConfig().getString("notificator.pushover.device", ""); // optional: - // your user's device name to send the message directly - // to that device, rather than all of the user's devices (multiple devices may be separated by a comma) - title = Context.getConfig().getString("notificator.pushover.title", ""); // optional: your message's title, - // otherwise your app's name is used + url = "https://api.pushover.net/1/messages.json"; } @Override public void sendSync(long userId, Event event, Position position) { + User user = Context.getPermissionsManager().getUser(userId); + + token = null; + puser = null; + device = null; + title = null; + + Properties properties = null; + + properties = getProperties(new PropertiesProvider(Context.getConfig())); + if (properties != null) { + token = properties.getProperty("notificator.pushover.token"); + puser = properties.getProperty("notificator.pushover.user"); + device = properties.getProperty("notificator.pushover.device"); + title = properties.getProperty("notificator.pushover.title"); + } + + properties = getProperties(new PropertiesProvider(user)); + if (properties != null) { + if (properties.getProperty("notificator.pushover.token") != null) { + token = properties.getProperty("notificator.pushover.token"); + } + if (properties.getProperty("notificator.pushover.user") != null) { + puser = properties.getProperty("notificator.pushover.user"); + } + if (properties.getProperty("notificator.pushover.device") != null) { + device = properties.getProperty("notificator.pushover.device"); + } + if (properties.getProperty("notificator.pushover.title") != null) { + title = properties.getProperty("notificator.pushover.title"); + } + } + + if (token == null) { + LOGGER.warn("Pushover token not found"); + return; + } + + if (puser == null) { + LOGGER.warn("Pushover user not found"); + return; + } + + if (device == null) + device = ""; + + if (title == null) + title = ""; + Message message = new Message(); message.token = token; - message.user = user; + message.user = puser; message.device = device; message.title = title; message.message = NotificationFormatter.formatShortMessage(userId, event, position); diff --git a/traccar-web b/traccar-web index e8479d77f..a587d6257 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit e8479d77f13acc3b3738a180a7990b06c495f1ba +Subproject commit a587d6257dd9de70252a5b00299ccbfd7b5cb272 -- cgit v1.2.3 From b27e8213f380f3ae8c2b9503e0aaecb55c784271 Mon Sep 17 00:00:00 2001 From: Andreas Date: Wed, 4 Mar 2020 21:47:19 +0100 Subject: correction for travis-ci --- .../java/org/traccar/notificators/NotificatorPushover.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index ae48bd46a..f289e464a 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -116,11 +116,11 @@ public class NotificatorPushover extends Notificator { if (properties.getProperty("notificator.pushover.device") != null) { device = properties.getProperty("notificator.pushover.device"); } - if (properties.getProperty("notificator.pushover.title") != null) { + if (properties.getProperty("notificator.pushover.title") != null) { title = properties.getProperty("notificator.pushover.title"); } - } - + } + if (token == null) { LOGGER.warn("Pushover token not found"); return; @@ -131,11 +131,13 @@ public class NotificatorPushover extends Notificator { return; } - if (device == null) + if (device == null) { device = ""; + } - if (title == null) + if (title == null) { title = ""; + } Message message = new Message(); message.token = token; -- cgit v1.2.3 From 6b7bec4554134517b2f1835d0eb86365e4a8fe42 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 4 Mar 2020 22:35:29 -0800 Subject: Fix RPM decoding --- src/main/java/org/traccar/protocol/BceProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java index 1b354c861..a259e027a 100644 --- a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java @@ -113,7 +113,7 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte()); } if (BitUtil.check(mask, 4)) { - position.set(Position.KEY_RPM, buf.readUnsignedShortLE() * 0.0125); + position.set(Position.KEY_RPM, buf.readUnsignedShortLE() * 0.125); } if (BitUtil.check(mask, 5)) { position.set(Position.KEY_HOURS, buf.readUnsignedIntLE()); -- cgit v1.2.3 From bc81692c898481cd71ddc54bf05c099796132b5f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 4 Mar 2020 22:40:46 -0800 Subject: Decode ignition value --- src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java | 7 ++++++- .../java/org/traccar/protocol/StarLinkProtocolDecoderTest.java | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java index bad6f03a9..2d1613e03 100644 --- a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 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. @@ -140,6 +140,11 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder { event = Integer.parseInt(data[i]); position.set(Position.KEY_ALARM, decodeAlarm(event)); position.set(Position.KEY_EVENT, event); + if (event == 24) { + position.set(Position.KEY_IGNITION, true); + } else if (event == 25) { + position.set(Position.KEY_IGNITION, false); + } break; case "#PDT#": position.setFixTime(dateFormat.parse(data[i])); diff --git a/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java index 97246a665..459dad978 100644 --- a/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java @@ -2,6 +2,7 @@ package org.traccar.protocol; import org.junit.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Position; public class StarLinkProtocolDecoderTest extends ProtocolTest { @@ -10,6 +11,14 @@ public class StarLinkProtocolDecoderTest extends ProtocolTest { StarLinkProtocolDecoder decoder = new StarLinkProtocolDecoder(null); + decoder.setFormat("#IMEI#,#EDT#,#PDT#,#LAT#,#LONG#,#SPD#,#IGN#,#ODO#,#DUR#,#TDUR#,#LAC#,#CID#,#VIN#,#VBAT#,#EID#,#EDSC#,#DRV#,#SATU#,#CSS#,#OUT1#,#OUT2#"); + + verifyAttribute(decoder, text( + "$SLU862549048472545,06,25,862549048472545,200304085936,200304085937,+4126.1828,+00209.8472,013.9,0,000000,,1,2120,6306,14.452,03.980,33,External Device,0,9,67,0,0,7,0,137,13,2,5625,-11,-20,99*1F"), + Position.KEY_IGNITION, false); + + decoder.setFormat("#EDT#,#EID#,#PDT#,#LAT#,#LONG#,#SPD#,#HEAD#,#ODO#,#IN1#,#IN2#,#IN3#,#IN4#,#OUT1#,#OUT2#,#OUT3#,#OUT4#,#LAC#,#CID#,#VIN#,#VBAT#,#DEST#,#IGN#,#ENG#"); + verifyAttributes(decoder, text( "$SLU068328,06,55,170518122023,16,,,,,,000000,1,1,0,0,0,0,0,0,10443,32722,12.664,03.910,,0,0,,01000001FDB3A9*BF")); -- cgit v1.2.3 From 7f1e024bca381f93cf1d9e61dadc3bb2f4943da7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 4 Mar 2020 22:55:06 -0800 Subject: Decode additional attributes --- .../traccar/protocol/OmnicommProtocolDecoder.java | 31 +++++++++++++++------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/traccar/protocol/OmnicommProtocolDecoder.java b/src/main/java/org/traccar/protocol/OmnicommProtocolDecoder.java index cd8b74c9a..6e9cf52a5 100644 --- a/src/main/java/org/traccar/protocol/OmnicommProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/OmnicommProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2020 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. @@ -111,16 +111,29 @@ public class OmnicommProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); + if (message.hasGeneral()) { + OmnicommMessageOuterClass.OmnicommMessage.General data = message.getGeneral(); + position.set(Position.KEY_POWER, data.getUboard() * 0.1); + position.set(Position.KEY_BATTERY_LEVEL, data.getBatLife()); + } + if (message.hasNAV()) { - OmnicommMessageOuterClass.OmnicommMessage.NAV nav = message.getNAV(); + OmnicommMessageOuterClass.OmnicommMessage.NAV data = message.getNAV(); position.setValid(true); - position.setTime(new Date((nav.getGPSTime() + 1230768000) * 1000L)); // from 2009-01-01 12:00 - position.setLatitude(nav.getLAT() * 0.0000001); - position.setLongitude(nav.getLON() * 0.0000001); - position.setSpeed(UnitsConverter.knotsFromKph(nav.getGPSVel() * 0.1)); - position.setCourse(nav.getGPSDir()); - position.setAltitude(nav.getGPSAlt() * 0.1); - position.set(Position.KEY_SATELLITES, nav.getGPSNSat()); + position.setTime(new Date((data.getGPSTime() + 1230768000) * 1000L)); // from 2009-01-01 12:00 + position.setLatitude(data.getLAT() * 0.0000001); + position.setLongitude(data.getLON() * 0.0000001); + position.setSpeed(UnitsConverter.knotsFromKph(data.getGPSVel() * 0.1)); + position.setCourse(data.getGPSDir()); + position.setAltitude(data.getGPSAlt() * 0.1); + position.set(Position.KEY_SATELLITES, data.getGPSNSat()); + } + + if (message.hasLLSDt()) { + OmnicommMessageOuterClass.OmnicommMessage.LLSDt data = message.getLLSDt(); + position.set("fuel1Temp", data.getTLLS1()); + position.set("fuel1", data.getCLLS1()); + position.set("fuel1State", data.getFLLS1()); } if (position.getFixTime() != null) { -- cgit v1.2.3 From 0443367a581100b4f9abd3d96a50793d80c93e45 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 5 Mar 2020 09:22:58 -0800 Subject: Fix coordinates decoding (fix #4496) --- src/main/java/org/traccar/protocol/TelicProtocolDecoder.java | 6 +++--- src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java b/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java index 457687b2e..efe155a88 100644 --- a/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2014 - 2020 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. @@ -42,8 +42,8 @@ public class TelicProtocolDecoder extends BaseProtocolDecoder { .number("(dd)(dd)(dd)") // date (ddmmyy) .number("(dd)(dd)(dd),") // time (hhmmss) .groupBegin() - .number("(-?d{9}),") // longitude - .number("(-?d{8}),") // latitude + .number("(-?d{7,}),") // longitude + .number("(-?d{6,}),") // latitude .or() .number("(-?d+),") // longitude .number("(-?d+),") // latitude diff --git a/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java index b743cef96..7616e7e8d 100644 --- a/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java @@ -13,6 +13,9 @@ public class TelicProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, text( "0026355565071347499|206|01|001002008")); + verifyPosition(decoder, text( + "023035467909228696525,280220174140,0,280220174135,-80333933,25796530,3,1,0,5,3,3,-21,319064,26202,0000,00,0,206,0,0407,0,0,18,0,3,0")); + verifyPosition(decoder, text( "052028495198,160917073641,0,160917073642,43879,511958,3,24,223,17,,,-3,142379,,0010,00,64,205,0,0499")); -- cgit v1.2.3 From 9bb835a9d45737d5090d1b78ee69310d59cb0a43 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 5 Mar 2020 09:26:06 -0800 Subject: Another minor fix --- src/main/java/org/traccar/protocol/TelicProtocolDecoder.java | 4 ++-- src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java b/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java index efe155a88..a4f9e2989 100644 --- a/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java @@ -42,8 +42,8 @@ public class TelicProtocolDecoder extends BaseProtocolDecoder { .number("(dd)(dd)(dd)") // date (ddmmyy) .number("(dd)(dd)(dd),") // time (hhmmss) .groupBegin() - .number("(-?d{7,}),") // longitude - .number("(-?d{6,}),") // latitude + .number("(-?d{8,}),") // longitude + .number("(-?d{7,}),") // latitude .or() .number("(-?d+),") // longitude .number("(-?d+),") // latitude diff --git a/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java index 7616e7e8d..3e3bafb34 100644 --- a/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java @@ -26,7 +26,8 @@ public class TelicProtocolDecoderTest extends ProtocolTest { "002135556507134749999,010817171138,0,010817171138,004560973,50667173,3,0,0,11,1,1,100,958071,20601,000000,00,4142,0000,0000,0208,10395,0")); verifyPosition(decoder, text( - "442045993198,290317131935,0,290317131935,269158,465748,3,26,183,,,,184,85316567,226,01,00,68,218")); + "442045993198,290317131935,0,290317131935,269158,465748,3,26,183,,,,184,85316567,226,01,00,68,218"), + position("2017-03-29 13:19:35.000", true, 46.57480, 26.91580)); verifyPosition(decoder, text( "673091036017,290317131801,0,290317131801,262214,450536,3,40,199,8,,,154,19969553,,0011,00,59,240,0,0406")); -- cgit v1.2.3 From e46cb0260f224ec296feb7087cdfb05371e6f550 Mon Sep 17 00:00:00 2001 From: Andreas Date: Thu, 5 Mar 2020 21:01:51 +0100 Subject: implement device in ui --- .../traccar/notificators/NotificatorPushover.java | 45 ++-------------------- traccar-web | 2 +- 2 files changed, 5 insertions(+), 42 deletions(-) diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index f289e464a..6cad6f766 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -36,36 +36,20 @@ public class NotificatorPushover extends Notificator { private static Properties getProperties(PropertiesProvider provider) { Properties properties = new Properties(); - // (required) token from pushover.net - String token = provider.getString("notificator.pushover.token"); - if (token != null) { - properties.put("notificator.pushover.token", token); - } - // (required) user from pushover.net - String user = provider.getString("notificator.pushover.user"); - if (user != null) { - properties.put("notificator.pushover.user", user); - } // optional: your user's device name to send the message directly // to that device, rather than all of the user's devices (multiple devices may be separated by a comma) String device = provider.getString("notificator.pushover.device"); if (device != null) { properties.put("notificator.pushover.device", device); } - // optional: your message's title, otherwise your app's name is used - String title = provider.getString("notificator.pushover.title"); - if (title != null) { - properties.put("notificator.pushover.title", title); - } return properties; } private final String url; - private String token; - private String puser; + private final String token; + private final String puser; private String device; - private String title; public static class Message { @JsonProperty("token") @@ -74,8 +58,6 @@ public class NotificatorPushover extends Notificator { private String user; @JsonProperty("device") private String device; - @JsonProperty("title") - private String title; @JsonProperty("message") private String message; } @@ -83,6 +65,8 @@ public class NotificatorPushover extends Notificator { public NotificatorPushover() { // see https://pushover.net/api url = "https://api.pushover.net/1/messages.json"; + token = Context.getConfig().getString("notificator.pushover.token"); // (required) token from pushover.net + puser = Context.getConfig().getString("notificator.pushover.user"); // (required) user from pushover.net } @Override @@ -90,35 +74,19 @@ public class NotificatorPushover extends Notificator { User user = Context.getPermissionsManager().getUser(userId); - token = null; - puser = null; device = null; - title = null; - Properties properties = null; properties = getProperties(new PropertiesProvider(Context.getConfig())); if (properties != null) { - token = properties.getProperty("notificator.pushover.token"); - puser = properties.getProperty("notificator.pushover.user"); device = properties.getProperty("notificator.pushover.device"); - title = properties.getProperty("notificator.pushover.title"); } properties = getProperties(new PropertiesProvider(user)); if (properties != null) { - if (properties.getProperty("notificator.pushover.token") != null) { - token = properties.getProperty("notificator.pushover.token"); - } - if (properties.getProperty("notificator.pushover.user") != null) { - puser = properties.getProperty("notificator.pushover.user"); - } if (properties.getProperty("notificator.pushover.device") != null) { device = properties.getProperty("notificator.pushover.device"); } - if (properties.getProperty("notificator.pushover.title") != null) { - title = properties.getProperty("notificator.pushover.title"); - } } if (token == null) { @@ -135,15 +103,10 @@ public class NotificatorPushover extends Notificator { device = ""; } - if (title == null) { - title = ""; - } - Message message = new Message(); message.token = token; message.user = puser; message.device = device; - message.title = title; message.message = NotificationFormatter.formatShortMessage(userId, event, position); Context.getClient().target(url).request() diff --git a/traccar-web b/traccar-web index a587d6257..071f08898 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit a587d6257dd9de70252a5b00299ccbfd7b5cb272 +Subproject commit 071f088980c867638f1092c48c6909a4433a0755 -- cgit v1.2.3 From 3c82764799784d3d30d969dbfef9a075f4874278 Mon Sep 17 00:00:00 2001 From: Vitaliy Gergel Date: Thu, 5 Mar 2020 22:22:59 +0200 Subject: Rename forward.urlVariables property --- src/main/java/org/traccar/WebDataHandler.java | 6 +++--- src/main/java/org/traccar/config/Keys.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java index 1af1af48a..d6bfb126b 100644 --- a/src/main/java/org/traccar/WebDataHandler.java +++ b/src/main/java/org/traccar/WebDataHandler.java @@ -67,7 +67,7 @@ public class WebDataHandler extends BaseDataHandler { private final String url; private final String header; private final boolean json; - private final boolean jsonUrlVariables; + private final boolean urlVariables; private final boolean retryEnabled; private final int retryDelay; @@ -86,7 +86,7 @@ public class WebDataHandler extends BaseDataHandler { this.url = config.getString(Keys.FORWARD_URL); this.header = config.getString(Keys.FORWARD_HEADER); this.json = config.getBoolean(Keys.FORWARD_JSON); - this.jsonUrlVariables = config.getBoolean(Keys.FORWARD_JSON_URL_VARIABLES); + this.urlVariables = config.getBoolean(Keys.FORWARD_URL_VARIABLES); this.retryEnabled = config.getBoolean(Keys.FORWARD_RETRY_ENABLE); this.retryDelay = config.getInteger(Keys.FORWARD_RETRY_DELAY, 100); @@ -194,7 +194,7 @@ public class WebDataHandler extends BaseDataHandler { String formattedUrl; try { - formattedUrl = (json && !jsonUrlVariables) ? url : formatRequest(position); + formattedUrl = (json && !urlVariables) ? url : formatRequest(position); } catch (UnsupportedEncodingException | JsonProcessingException e) { throw new RuntimeException("Forwarding formatting error", e); } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index a5b7b780c..200ef8aa3 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -104,8 +104,8 @@ public final class Keys { * Boolean value to enable URL parameters in json mode. For example, {uniqueId} for device identifier, * {latitude} and {longitude} for coordinates. */ - public static final ConfigKey FORWARD_JSON_URL_VARIABLES = new ConfigKey( - "forward.json.url.variables", Boolean.class); + public static final ConfigKey FORWARD_URL_VARIABLES = new ConfigKey( + "forward.urlVariables", Boolean.class); /** * Position forwarding retrying enable. When enabled, additional attempts are made to deliver positions. If initial -- cgit v1.2.3 From 7eecff54effb04d27fdd1d67ed75a1e2dbc3c693 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 5 Mar 2020 22:21:45 -0800 Subject: Support OKO AVTO format --- .../org/traccar/protocol/OkoProtocolDecoder.java | 23 +++++++++++++++------- .../traccar/protocol/OkoProtocolDecoderTest.java | 6 ++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/OkoProtocolDecoder.java b/src/main/java/org/traccar/protocol/OkoProtocolDecoder.java index 5adf61494..4d9c9afc4 100644 --- a/src/main/java/org/traccar/protocol/OkoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/OkoProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 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. @@ -36,7 +36,7 @@ public class OkoProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN = new PatternBuilder() .text("{") .number("(d{15}),").optional() // imei - .number("(dd)(dd)(dd).d+,") // time + .number("(dd)(dd)(dd)(?:.d+)?,") // time .expression("([AV]),") // validity .number("(dd)(dd.d+),") // latitude .expression("([NS]),") @@ -46,14 +46,23 @@ public class OkoProtocolDecoder extends BaseProtocolDecoder { .number("(d+.?d*)?,") // course .number("(dd)(dd)(dd),") // date (ddmmyy) .number("(d+),") // satellites - .number("(d+.d+),") // adc + .number("(d+.d+|xx),") // adc .number("(xx),") // event - .number("(d+.d+),") // power + .number("(d+.d+|xx),") // power .number("d,") // memory status - .number("(xx)") // io + .number("(xx)?") // io .any() .compile(); + private double decodeVoltage(Parser parser) { + String value = parser.next(); + if (value.contains(".")) { + return Double.parseDouble(value); + } else { + return Integer.parseInt(value, 16) * 0.1; + } + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -89,9 +98,9 @@ public class OkoProtocolDecoder extends BaseProtocolDecoder { position.setTime(dateBuilder.getDate()); position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + position.set(Position.PREFIX_ADC + 1, decodeVoltage(parser)); position.set(Position.KEY_EVENT, parser.next()); - position.set(Position.KEY_POWER, parser.nextDouble()); + position.set(Position.KEY_POWER, decodeVoltage(parser)); position.set(Position.KEY_INPUT, parser.nextHexInt()); return position; diff --git a/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java index e2f72c161..d6b8e9a4a 100644 --- a/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java @@ -10,6 +10,12 @@ public class OkoProtocolDecoderTest extends ProtocolTest { OkoProtocolDecoder decoder = new OkoProtocolDecoder(null); + verifyPosition(decoder, text( + "{868204000482330,125138,A,5026.821,N,03032.472,E,0.0,171,240200,7,00,F9,7D,1,,,,,,,91,,,187.7,M,2,,}")); + + verifyPosition(decoder, text( + "{123456789098765,132810.000,A,4926.4243,N,03203.6831,E,0.08,83.52,131010,07,5C,FB,7A,1,27,,,,,,CB,128,15grn,197.6,M,3,01FE,02AC}")); + verifyPosition(decoder, text( "{861694033681089,045403.00,A,4924.14181,N,03207.43787,E,0.080,,151117,07,0.00,01,24.8,1,02,5n4}")); -- cgit v1.2.3 From d2835b2c6152b448179c0ecae6c9aadc4dce60a6 Mon Sep 17 00:00:00 2001 From: Andreas Date: Fri, 6 Mar 2020 16:51:15 +0100 Subject: simplify code --- .../traccar/notificators/NotificatorPushover.java | 42 +++++----------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index 6cad6f766..5c86503f3 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -21,11 +21,8 @@ import org.slf4j.LoggerFactory; import org.traccar.Context; import org.traccar.model.Event; import org.traccar.model.Position; -import org.traccar.notification.NotificationFormatter; - import org.traccar.model.User; -import org.traccar.notification.PropertiesProvider; -import java.util.Properties; +import org.traccar.notification.NotificationFormatter; import javax.ws.rs.client.Entity; import javax.ws.rs.client.InvocationCallback; @@ -34,22 +31,9 @@ public class NotificatorPushover extends Notificator { private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorPushover.class); - private static Properties getProperties(PropertiesProvider provider) { - Properties properties = new Properties(); - // optional: your user's device name to send the message directly - // to that device, rather than all of the user's devices (multiple devices may be separated by a comma) - String device = provider.getString("notificator.pushover.device"); - if (device != null) { - properties.put("notificator.pushover.device", device); - } - return properties; - } - - private final String url; private final String token; private final String puser; - private String device; public static class Message { @JsonProperty("token") @@ -72,21 +56,15 @@ public class NotificatorPushover extends Notificator { @Override public void sendSync(long userId, Event event, Position position) { - User user = Context.getPermissionsManager().getUser(userId); - - device = null; - Properties properties = null; + final User user = Context.getPermissionsManager().getUser(userId); - properties = getProperties(new PropertiesProvider(Context.getConfig())); - if (properties != null) { - device = properties.getProperty("notificator.pushover.device"); - } + String device = ""; - properties = getProperties(new PropertiesProvider(user)); - if (properties != null) { - if (properties.getProperty("notificator.pushover.device") != null) { - device = properties.getProperty("notificator.pushover.device"); - } + if (user.getAttributes().containsKey("notificator.pushover.device")) { + // optional: your user's device name to send the message directly + // to that device, rather than all of the user's devices (multiple devices may be separated by a comma) + // i.e.: device1,device2 (no space) + device = user.getString("notificator.pushover.device").replaceAll(" *, *", ","); } if (token == null) { @@ -99,10 +77,6 @@ public class NotificatorPushover extends Notificator { return; } - if (device == null) { - device = ""; - } - Message message = new Message(); message.token = token; message.user = puser; -- cgit v1.2.3 From c1b640ef2736b5f3a16440c8fbb12db6ad3bdb56 Mon Sep 17 00:00:00 2001 From: Andreas Date: Fri, 6 Mar 2020 19:41:04 +0100 Subject: change copyright date --- src/main/java/org/traccar/notificators/NotificatorPushover.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index 5c86503f3..52646bdfb 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2020 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. -- cgit v1.2.3 From fa837208bed12dd08e1a540a2279180dec102974 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 6 Mar 2020 21:29:27 -0800 Subject: Support Traxsit GPS1 format --- .../org/traccar/protocol/SigfoxProtocolDecoder.java | 18 +++++++++++++----- .../traccar/protocol/SigfoxProtocolDecoderTest.java | 3 +++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java index 304f61836..bda0600cc 100644 --- a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 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. @@ -83,7 +83,14 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { } JsonObject json = Json.createReader(new StringReader(content)).readObject(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, json.getString("device")); + String deviceId; + if (json.containsKey("device")) { + deviceId = json.getString("device"); + } else { + deviceId = json.getString("deviceId"); + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, deviceId); if (deviceSession == null) { sendResponse(channel, HttpResponseStatus.BAD_REQUEST); return null; @@ -99,7 +106,8 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { } if (json.containsKey("location") - || json.containsKey("lat") && json.containsKey("lng") && !json.containsKey("data")) { + || json.containsKey("lat") && json.containsKey("lng") && !json.containsKey("data") + || json.containsKey("latitude") && json.containsKey("longitude") && !json.containsKey("data")) { JsonObject location; if (json.containsKey("location")) { @@ -109,8 +117,8 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { } position.setValid(true); - position.setLatitude(getJsonDouble(location, "lat")); - position.setLongitude(getJsonDouble(location, "lng")); + position.setLatitude(getJsonDouble(location, location.containsKey("lat") ? "lat" : "latitude")); + position.setLongitude(getJsonDouble(location, location.containsKey("lng") ? "lng" : "longitude")); } else { diff --git a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java index 4ab343876..2bf6276b3 100644 --- a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java @@ -12,6 +12,9 @@ public class SigfoxProtocolDecoderTest extends ProtocolTest { SigfoxProtocolDecoder decoder = new SigfoxProtocolDecoder(null); + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("{\"deviceId\":\"3377BC\",\"snr\":\"16.46\",\"rssi\":\"-123.00\",\"station\":\"-123.00\",\"seqNum\":\"3042\",\"newPosition\":true,\"latitude\":51.9189749,\"longitude\":-8.3979322,\"positionTime\":\"1582801850\",\"moving\":false,\"magChange\":false,\"magStatus\":false,\"temperature\":-2,\"battery\":\"null\",\"batteryPercentage\":\"null\",\"lastSeen\":\"1582801850\",\"fwVersion\":\"null\",\"dlConfig\":\"null\",\"recievedPayload\":\"09495a9085f5c94c\"}"))); + verifyPosition(decoder, request(HttpMethod.POST, "/", buffer("{ \"device\" : \"33827B\", \"data\" : \"1f03198e63807f08836402ff\", \"time\" : \"1574346702\", \"snr\" : \"8.82\", \"station\" : \"140A\", \"avgSnr\" : \"11.28\", \"lat\" : \"52.0\", \"lng\" : \"-8.0\", \"rssi\" : \"-141.00\", \"seqNumber\" : \"3662\"}"))); -- cgit v1.2.3 From 38efcf3dbc8a46b9797e5fb654fc1c68815b3b36 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 7 Mar 2020 09:50:49 -0800 Subject: Update response message --- src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java index 382509793..ab89f10c8 100644 --- a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java @@ -97,7 +97,7 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { rootElement.appendChild(state); Element stateMessage = document.createElement("stateMessage"); - stateMessage.appendChild(document.createTextNode("Messages received and stored successfully")); + stateMessage.appendChild(document.createTextNode("Store OK")); rootElement.appendChild(stateMessage); Transformer transformer = TransformerFactory.newInstance().newTransformer(); -- cgit v1.2.3 From 405728ba652f6305ee39833b7d4867bb1df7db2f Mon Sep 17 00:00:00 2001 From: Andreas Date: Sat, 7 Mar 2020 20:03:34 +0100 Subject: clean submodule --- traccar-web | 1 - 1 file changed, 1 deletion(-) delete mode 160000 traccar-web diff --git a/traccar-web b/traccar-web deleted file mode 160000 index 071f08898..000000000 --- a/traccar-web +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 071f088980c867638f1092c48c6909a4433a0755 -- cgit v1.2.3 From 679c782f9e464b746e5431a84893229c74fc6c66 Mon Sep 17 00:00:00 2001 From: Andreas Date: Sat, 7 Mar 2020 20:35:53 +0100 Subject: remove submodule --- traccar-web | 1 + 1 file changed, 1 insertion(+) create mode 160000 traccar-web diff --git a/traccar-web b/traccar-web new file mode 160000 index 000000000..e8479d77f --- /dev/null +++ b/traccar-web @@ -0,0 +1 @@ +Subproject commit e8479d77f13acc3b3738a180a7990b06c495f1ba -- cgit v1.2.3 From 9caf803986d14661e2e1842b80ee3aa58c8d5c6d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 7 Mar 2020 11:45:52 -0800 Subject: Remove comments --- src/main/java/org/traccar/notificators/NotificatorPushover.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index 52646bdfb..141d652ca 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -47,10 +47,9 @@ public class NotificatorPushover extends Notificator { } public NotificatorPushover() { - // see https://pushover.net/api url = "https://api.pushover.net/1/messages.json"; - token = Context.getConfig().getString("notificator.pushover.token"); // (required) token from pushover.net - puser = Context.getConfig().getString("notificator.pushover.user"); // (required) user from pushover.net + token = Context.getConfig().getString("notificator.pushover.token"); + puser = Context.getConfig().getString("notificator.pushover.user"); } @Override @@ -61,9 +60,6 @@ public class NotificatorPushover extends Notificator { String device = ""; if (user.getAttributes().containsKey("notificator.pushover.device")) { - // optional: your user's device name to send the message directly - // to that device, rather than all of the user's devices (multiple devices may be separated by a comma) - // i.e.: device1,device2 (no space) device = user.getString("notificator.pushover.device").replaceAll(" *, *", ","); } -- cgit v1.2.3 From 26cc87fd06b94400ee769e8c2985778b3b6e8ff6 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 11 Mar 2020 21:09:09 -0700 Subject: Decode additional attributes --- .../java/org/traccar/protocol/SigfoxProtocolDecoder.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java index bda0600cc..c2c3d0fc3 100644 --- a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java @@ -101,10 +101,16 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { if (json.containsKey("time")) { position.setTime(new Date(getJsonInt(json, "time") * 1000L)); + } else if (json.containsKey("positionTime")) { + position.setTime(new Date(getJsonInt(json, "positionTime") * 1000L)); } else { position.setTime(new Date()); } + if (json.containsKey("lastSeen")) { + position.setDeviceTime(new Date(getJsonInt(json, "lastSeen") * 1000L)); + } + if (json.containsKey("location") || json.containsKey("lat") && json.containsKey("lng") && !json.containsKey("data") || json.containsKey("latitude") && json.containsKey("longitude") && !json.containsKey("data")) { @@ -120,6 +126,16 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { position.setLatitude(getJsonDouble(location, location.containsKey("lat") ? "lat" : "latitude")); position.setLongitude(getJsonDouble(location, location.containsKey("lng") ? "lng" : "longitude")); + if (location.containsKey("moving")) { + position.set(Position.KEY_MOTION, location.getBoolean("moving")); + } + if (location.containsKey("magStatus")) { + position.set(Position.KEY_BLOCKED, location.getBoolean("magStatus")); + } + if (location.containsKey("temperature")) { + position.set(Position.KEY_DEVICE_TEMP, location.getJsonNumber("temperature").doubleValue()); + } + } else { String data = json.getString(json.containsKey("data") ? "data" : "payload"); -- cgit v1.2.3 From 578a8544bc0d31569fabbc8c3aa26a53d161d5ed Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 11 Mar 2020 21:17:02 -0700 Subject: Fix response index --- .../java/org/traccar/protocol/EskyProtocolDecoder.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java b/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java index f0ae0bc91..1a4f9b906 100644 --- a/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java @@ -38,7 +38,7 @@ public class EskyProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN = new PatternBuilder() .expression("..;") // header - .number("(d+);") // index + .number("d+;") .number("(d+);") // imei .text("R;") // data type .number("(d+)[+;]") // satellites @@ -61,16 +61,12 @@ public class EskyProtocolDecoder extends BaseProtocolDecoder { protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - Parser parser = new Parser(PATTERN, (String) msg); + String sentence = (String) msg; + Parser parser = new Parser(PATTERN, sentence); if (!parser.matches()) { return null; } - int index = parser.nextInt(); - if (channel instanceof DatagramChannel) { - channel.writeAndFlush(new NetworkMessage("ACK," + index + "#", remoteAddress)); - } - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); if (deviceSession == null) { return null; @@ -99,6 +95,11 @@ public class EskyProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); + int index = sentence.lastIndexOf('+'); + if (index > 0 && channel instanceof DatagramChannel) { + channel.writeAndFlush(new NetworkMessage("ACK," + sentence.substring(index + 1) + "#", remoteAddress)); + } + return position; } -- cgit v1.2.3 From 1fdb7794514d59fef165d647f0b9ccf5db271621 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 12 Mar 2020 21:27:59 -0700 Subject: Add a test case --- .../java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java index b040d4ecf..4e08ce7a5 100644 --- a/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java @@ -2,6 +2,7 @@ package org.traccar.protocol; import org.junit.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Position; public class SolarPoweredProtocolDecoderTest extends ProtocolTest { @@ -10,6 +11,10 @@ public class SolarPoweredProtocolDecoderTest extends ProtocolTest { SolarPoweredProtocolDecoder decoder = new SolarPoweredProtocolDecoder(null); + verifyAttribute(decoder, binary( + "7e850256553309440011003e81131914030600332301a61ed709209ff40014b89082020f0283100000f908000000440000003d1f19021784114161726f6e34475630312d323030333031057e"), + Position.KEY_RSSI, 23); + verifyPosition(decoder, binary( "7e850256553304728011003e811319130b0b11211f01a2e6be091fa0e10114cc1582020f00831000004e7400000044000000223819020c84114161726f6e34475630312d313931303331127e")); -- cgit v1.2.3 From e2071c06c0962c083f4f4d5dce5961b08c1920e7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 14 Mar 2020 16:22:47 -0700 Subject: Decode more alarms --- .../traccar/protocol/FifotrackProtocolDecoder.java | 28 +++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java index 40e146e0b..9bc7cb504 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2020 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. @@ -116,6 +116,32 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { return Position.ALARM_POWER_CUT; case 16: return Position.ALARM_POWER_RESTORED; + case 17: + return Position.ALARM_LOW_BATTERY; + case 18: + return Position.ALARM_OVERSPEED; + case 20: + return Position.ALARM_GPS_ANTENNA_CUT; + case 21: + return Position.ALARM_VIBRATION; + case 23: + return Position.ALARM_ACCELERATION; + case 24: + return Position.ALARM_BRAKING; + case 27: + return Position.ALARM_FATIGUE_DRIVING; + case 30: + case 32: + return Position.ALARM_JAMMING; + case 33: + return Position.ALARM_GEOFENCE_EXIT; + case 34: + return Position.ALARM_GEOFENCE_ENTER; + case 35: + return Position.ALARM_IDLE; + case 40: + case 41: + return Position.ALARM_TEMPERATURE; default: return null; } -- cgit v1.2.3 From 57c977d8369c96787c778ac2c27769ec53f24a6e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 15 Mar 2020 14:47:36 -0700 Subject: Improve type casting --- src/main/java/org/traccar/BaseProtocolDecoder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java index e6e02c2d6..634ceafd5 100644 --- a/src/main/java/org/traccar/BaseProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2020 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. @@ -227,9 +227,9 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { if (decodedMessage instanceof Position) { position = (Position) decodedMessage; } else if (decodedMessage instanceof Collection) { - Collection positions = (Collection) decodedMessage; + Collection positions = (Collection) decodedMessage; if (!positions.isEmpty()) { - position = (Position) positions.iterator().next(); + position = positions.iterator().next(); } } } -- cgit v1.2.3 From c43208bf5339244cd9a47348ec9daa1805099718 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 15 Mar 2020 15:03:43 -0700 Subject: Remove extra method --- src/main/java/org/traccar/BaseProtocol.java | 7 +------ src/main/java/org/traccar/protocol/WondexProtocol.java | 11 +++++++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/BaseProtocol.java b/src/main/java/org/traccar/BaseProtocol.java index c0fd1e27f..6d459f7d4 100644 --- a/src/main/java/org/traccar/BaseProtocol.java +++ b/src/main/java/org/traccar/BaseProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2020 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. @@ -68,11 +68,6 @@ public abstract class BaseProtocol implements Protocol { supportedTextCommands.addAll(Arrays.asList(commands)); } - public void setSupportedCommands(String... commands) { - supportedDataCommands.addAll(Arrays.asList(commands)); - supportedTextCommands.addAll(Arrays.asList(commands)); - } - @Override public Collection getSupportedDataCommands() { Set commands = new HashSet<>(supportedDataCommands); diff --git a/src/main/java/org/traccar/protocol/WondexProtocol.java b/src/main/java/org/traccar/protocol/WondexProtocol.java index 035dd9160..6401fde85 100644 --- a/src/main/java/org/traccar/protocol/WondexProtocol.java +++ b/src/main/java/org/traccar/protocol/WondexProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2020 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. @@ -25,7 +25,7 @@ import io.netty.handler.codec.string.StringEncoder; public class WondexProtocol extends BaseProtocol { public WondexProtocol() { - setSupportedCommands( + setSupportedDataCommands( Command.TYPE_GET_DEVICE_STATUS, Command.TYPE_GET_MODEM_STATUS, Command.TYPE_REBOOT_DEVICE, @@ -33,6 +33,13 @@ public class WondexProtocol extends BaseProtocol { Command.TYPE_GET_VERSION, Command.TYPE_IDENTIFICATION); setTextCommandEncoder(new WondexProtocolEncoder(this)); + setSupportedTextCommands( + Command.TYPE_GET_DEVICE_STATUS, + Command.TYPE_GET_MODEM_STATUS, + Command.TYPE_REBOOT_DEVICE, + Command.TYPE_POSITION_SINGLE, + Command.TYPE_GET_VERSION, + Command.TYPE_IDENTIFICATION); addServer(new TrackerServer(false, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { -- cgit v1.2.3 From f98c3aa5b65e9fa06bcea38d96959b43f6a38245 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 15 Mar 2020 15:39:12 -0700 Subject: Simplify data commands --- src/main/java/org/traccar/BaseProtocol.java | 15 +++++++++------ src/main/java/org/traccar/Protocol.java | 4 +++- src/main/java/org/traccar/database/ActiveDevice.java | 8 ++------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/traccar/BaseProtocol.java b/src/main/java/org/traccar/BaseProtocol.java index 6d459f7d4..bd3391822 100644 --- a/src/main/java/org/traccar/BaseProtocol.java +++ b/src/main/java/org/traccar/BaseProtocol.java @@ -15,12 +15,14 @@ */ package org.traccar; +import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; import io.netty.handler.codec.string.StringEncoder; -import org.traccar.database.ActiveDevice; import org.traccar.helper.DataConverter; import org.traccar.model.Command; +import java.net.SocketAddress; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; @@ -83,15 +85,16 @@ public abstract class BaseProtocol implements Protocol { } @Override - public void sendDataCommand(ActiveDevice activeDevice, Command command) { + public void sendDataCommand(Channel channel, SocketAddress remoteAddress, Command command) { if (supportedDataCommands.contains(command.getType())) { - activeDevice.write(command); + channel.writeAndFlush(new NetworkMessage(command, remoteAddress)); } else if (command.getType().equals(Command.TYPE_CUSTOM)) { String data = command.getString(Command.KEY_DATA); - if (BasePipelineFactory.getHandler(activeDevice.getChannel().pipeline(), StringEncoder.class) != null) { - activeDevice.write(data); + if (BasePipelineFactory.getHandler(channel.pipeline(), StringEncoder.class) != null) { + channel.writeAndFlush(new NetworkMessage(data, remoteAddress)); } else { - activeDevice.write(Unpooled.wrappedBuffer(DataConverter.parseHex(data))); + ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(data)); + channel.writeAndFlush(new NetworkMessage(buf, remoteAddress)); } } else { throw new RuntimeException("Command " + command.getType() + " is not supported in protocol " + getName()); diff --git a/src/main/java/org/traccar/Protocol.java b/src/main/java/org/traccar/Protocol.java index 3b66f2598..9d257be78 100644 --- a/src/main/java/org/traccar/Protocol.java +++ b/src/main/java/org/traccar/Protocol.java @@ -15,9 +15,11 @@ */ package org.traccar; +import io.netty.channel.Channel; import org.traccar.database.ActiveDevice; import org.traccar.model.Command; +import java.net.SocketAddress; import java.util.Collection; public interface Protocol { @@ -28,7 +30,7 @@ public interface Protocol { Collection getSupportedDataCommands(); - void sendDataCommand(ActiveDevice activeDevice, Command command); + void sendDataCommand(Channel channel, SocketAddress remoteAddress, Command command); Collection getSupportedTextCommands(); diff --git a/src/main/java/org/traccar/database/ActiveDevice.java b/src/main/java/org/traccar/database/ActiveDevice.java index 207fc454b..698cc851e 100644 --- a/src/main/java/org/traccar/database/ActiveDevice.java +++ b/src/main/java/org/traccar/database/ActiveDevice.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2020 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. @@ -45,11 +45,7 @@ public class ActiveDevice { } public void sendCommand(Command command) { - protocol.sendDataCommand(this, command); - } - - public void write(Object message) { - channel.writeAndFlush(new NetworkMessage(message, remoteAddress)); + protocol.sendDataCommand(channel, remoteAddress, command); } } -- cgit v1.2.3 From f9257e664be8c37cc041e004f403d737dd513d6b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 15 Mar 2020 15:43:17 -0700 Subject: Remove unused imports --- src/main/java/org/traccar/Protocol.java | 3 +-- src/main/java/org/traccar/database/ActiveDevice.java | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/Protocol.java b/src/main/java/org/traccar/Protocol.java index 9d257be78..aea69b353 100644 --- a/src/main/java/org/traccar/Protocol.java +++ b/src/main/java/org/traccar/Protocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2020 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. @@ -16,7 +16,6 @@ package org.traccar; import io.netty.channel.Channel; -import org.traccar.database.ActiveDevice; import org.traccar.model.Command; import java.net.SocketAddress; diff --git a/src/main/java/org/traccar/database/ActiveDevice.java b/src/main/java/org/traccar/database/ActiveDevice.java index 698cc851e..34b3de227 100644 --- a/src/main/java/org/traccar/database/ActiveDevice.java +++ b/src/main/java/org/traccar/database/ActiveDevice.java @@ -16,7 +16,6 @@ package org.traccar.database; import io.netty.channel.Channel; -import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.model.Command; -- cgit v1.2.3 From 6adcd4a8dd950a5f945c818280974a0302c9fd8b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 15 Mar 2020 15:46:27 -0700 Subject: Remove duplication --- src/main/java/org/traccar/BaseProtocolDecoder.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java index 634ceafd5..d014b0871 100644 --- a/src/main/java/org/traccar/BaseProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -233,16 +233,18 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { } } } + long deviceId = 0; if (position != null) { - connectionManager.updateDevice( - position.getDeviceId(), Device.STATUS_ONLINE, new Date()); + deviceId = position.getDeviceId(); } else { DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); if (deviceSession != null) { - connectionManager.updateDevice( - deviceSession.getDeviceId(), Device.STATUS_ONLINE, new Date()); + deviceId = deviceSession.getDeviceId(); } } + if (deviceId > 0) { + connectionManager.updateDevice(deviceId, Device.STATUS_ONLINE, new Date()); + } } @Override -- cgit v1.2.3 From 11dcacc2fdfd29f4440c8c46e501ef565f9b1dfd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 15 Mar 2020 15:58:52 -0700 Subject: Decoder to send queued commands --- src/main/java/org/traccar/BaseProtocolDecoder.java | 12 ++++++++++++ src/main/java/org/traccar/database/CommandsManager.java | 14 ++++++++++---- src/main/java/org/traccar/database/ConnectionManager.java | 4 ---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java index d014b0871..8981fe4c8 100644 --- a/src/main/java/org/traccar/BaseProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -21,10 +21,12 @@ import io.netty.handler.codec.http.HttpRequestDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; +import org.traccar.database.CommandsManager; import org.traccar.database.ConnectionManager; import org.traccar.database.IdentityManager; import org.traccar.database.StatisticsManager; import org.traccar.helper.UnitsConverter; +import org.traccar.model.Command; import org.traccar.model.Device; import org.traccar.model.Position; @@ -245,6 +247,16 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { if (deviceId > 0) { connectionManager.updateDevice(deviceId, Device.STATUS_ONLINE, new Date()); } + sendQueuedCommands(channel, remoteAddress, deviceId); + } + + protected void sendQueuedCommands(Channel channel, SocketAddress remoteAddress, long deviceId) { + CommandsManager commandsManager = Context.getCommandsManager(); + if (commandsManager != null) { + for (Command command : commandsManager.readQueuedCommands(deviceId)) { + protocol.sendDataCommand(channel, remoteAddress, command); + } + } } @Override diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java index de6eeeba8..99114db5e 100644 --- a/src/main/java/org/traccar/database/CommandsManager.java +++ b/src/main/java/org/traccar/database/CommandsManager.java @@ -161,21 +161,27 @@ public class CommandsManager extends ExtendedObjectManager { } } - public void sendQueuedCommands(ActiveDevice activeDevice) { + public Collection readQueuedCommands(long deviceId) { + return readQueuedCommands(deviceId, Integer.MAX_VALUE); + } + + public Collection readQueuedCommands(long deviceId, int count) { Queue deviceQueue; try { readLock(); - deviceQueue = deviceQueues.get(activeDevice.getDeviceId()); + deviceQueue = deviceQueues.get(deviceId); } finally { readUnlock(); } + Collection result = new ArrayList<>(); if (deviceQueue != null) { Command command = deviceQueue.poll(); - while (command != null) { - activeDevice.sendCommand(command); + while (command != null && result.size() < count) { + result.add(command); command = deviceQueue.poll(); } } + return result; } } diff --git a/src/main/java/org/traccar/database/ConnectionManager.java b/src/main/java/org/traccar/database/ConnectionManager.java index dd0071143..4d43bc71b 100644 --- a/src/main/java/org/traccar/database/ConnectionManager.java +++ b/src/main/java/org/traccar/database/ConnectionManager.java @@ -139,10 +139,6 @@ public class ConnectionManager { } updateDevice(device); - - if (status.equals(Device.STATUS_ONLINE) && !oldStatus.equals(Device.STATUS_ONLINE)) { - Context.getCommandsManager().sendQueuedCommands(getActiveDevice(deviceId)); - } } public Map updateDeviceState(long deviceId) { -- cgit v1.2.3 From 606afeb37451f921fe3aecffab439cc2bcc7a175 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 15 Mar 2020 16:02:37 -0700 Subject: Queue HTTP commands --- src/main/java/org/traccar/database/ActiveDevice.java | 6 ++++++ src/main/java/org/traccar/database/CommandsManager.java | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/database/ActiveDevice.java b/src/main/java/org/traccar/database/ActiveDevice.java index 34b3de227..e3ece6ad9 100644 --- a/src/main/java/org/traccar/database/ActiveDevice.java +++ b/src/main/java/org/traccar/database/ActiveDevice.java @@ -16,6 +16,8 @@ package org.traccar.database; import io.netty.channel.Channel; +import io.netty.handler.codec.http.HttpRequestDecoder; +import org.traccar.BasePipelineFactory; import org.traccar.Protocol; import org.traccar.model.Command; @@ -43,6 +45,10 @@ public class ActiveDevice { return deviceId; } + public boolean supportsLiveCommands() { + return BasePipelineFactory.getHandler(channel.pipeline(), HttpRequestDecoder.class) == null; + } + public void sendCommand(Command command) { protocol.sendDataCommand(channel, remoteAddress, command); } diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java index 99114db5e..485402807 100644 --- a/src/main/java/org/traccar/database/CommandsManager.java +++ b/src/main/java/org/traccar/database/CommandsManager.java @@ -76,7 +76,12 @@ public class CommandsManager extends ExtendedObjectManager { } else { ActiveDevice activeDevice = Context.getConnectionManager().getActiveDevice(deviceId); if (activeDevice != null) { - activeDevice.sendCommand(command); + if (activeDevice.supportsLiveCommands()) { + activeDevice.sendCommand(command); + } else { + getDeviceQueue(deviceId).add(command); + return false; + } } else if (!queueing) { throw new RuntimeException("Device is not online"); } else { -- cgit v1.2.3 From 83494fe445a9c7cb4f6b7de1e97e0d257f8bc7c2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 15 Mar 2020 16:13:52 -0700 Subject: Support HTTP response content --- src/main/java/org/traccar/BaseHttpProtocolDecoder.java | 15 ++++++++++++--- .../org/traccar/protocol/LeafSpyProtocolDecoder.java | 7 +------ .../org/traccar/protocol/PiligrimProtocolDecoder.java | 17 ++++------------- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/traccar/BaseHttpProtocolDecoder.java b/src/main/java/org/traccar/BaseHttpProtocolDecoder.java index 57a68acac..b762be12c 100644 --- a/src/main/java/org/traccar/BaseHttpProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseHttpProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2020 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. @@ -15,6 +15,8 @@ */ package org.traccar; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.HttpHeaderNames; @@ -29,9 +31,16 @@ public abstract class BaseHttpProtocolDecoder extends BaseProtocolDecoder { } public void sendResponse(Channel channel, HttpResponseStatus status) { + sendResponse(channel, status, null); + } + + public void sendResponse(Channel channel, HttpResponseStatus status, ByteBuf buf) { if (channel != null) { - HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status); - response.headers().add(HttpHeaderNames.CONTENT_LENGTH, 0); + if (buf == null) { + buf = Unpooled.buffer(0); + } + HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, buf); + response.headers().add(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes()); channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); } } diff --git a/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java b/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java index 5b352a961..8b47701fd 100644 --- a/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java @@ -122,13 +122,8 @@ public class LeafSpyProtocolDecoder extends BaseHttpProtocolDecoder { } if (position.getDeviceId() != 0) { - if (channel != null) { - HttpResponse response = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, - HttpResponseStatus.OK, + sendResponse(channel, HttpResponseStatus.OK, Unpooled.copiedBuffer("\"status\":\"0\"", StandardCharsets.US_ASCII)); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } return position; } else { sendResponse(channel, HttpResponseStatus.BAD_REQUEST); diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index 47aa86da7..26ce2fe53 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2014 - 2020 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. @@ -18,15 +18,11 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; -import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.QueryStringDecoder; -import org.traccar.BaseProtocolDecoder; +import org.traccar.BaseHttpProtocolDecoder; import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.BitUtil; import org.traccar.helper.DateBuilder; @@ -37,19 +33,14 @@ import java.nio.charset.StandardCharsets; import java.util.LinkedList; import java.util.List; -public class PiligrimProtocolDecoder extends BaseProtocolDecoder { +public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { public PiligrimProtocolDecoder(Protocol protocol) { super(protocol); } private void sendResponse(Channel channel, String message) { - if (channel != null) { - FullHttpResponse response = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, HttpResponseStatus.OK, - Unpooled.copiedBuffer(message, StandardCharsets.US_ASCII)); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } + sendResponse(channel, HttpResponseStatus.OK, Unpooled.copiedBuffer(message, StandardCharsets.US_ASCII)); } public static final int MSG_GPS = 0xF1; -- cgit v1.2.3 From 0164474c700337c686fea93e2ca4875adaaf35d5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 15 Mar 2020 16:17:07 -0700 Subject: Remove unused imports --- src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java b/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java index 8b47701fd..ad0c9bd32 100644 --- a/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2020 Anton Tananaev (anton@traccar.org) * Copyright 2019 Jesse Hills (jesserockz@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,16 +19,12 @@ package org.traccar.protocol; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.QueryStringDecoder; import org.traccar.BaseHttpProtocolDecoder; import org.traccar.DeviceSession; import org.traccar.Protocol; import org.traccar.model.Position; -import org.traccar.NetworkMessage; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; -- cgit v1.2.3 From f85af44e180c87993d2d8d760f64af775f99531f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 15 Mar 2020 16:22:35 -0700 Subject: Support commands for OsmAnd --- .../traccar/protocol/OsmAndProtocolDecoder.java | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java b/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java index 3bc71de81..ec9bbc240 100644 --- a/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2020 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. @@ -15,15 +15,19 @@ */ package org.traccar.protocol; +import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.QueryStringDecoder; import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.Context; import org.traccar.DeviceSession; import org.traccar.Protocol; +import org.traccar.database.CommandsManager; import org.traccar.helper.DateUtil; import org.traccar.model.CellTower; +import org.traccar.model.Command; import org.traccar.model.Network; import org.traccar.model.Position; import org.traccar.model.WifiAccessPoint; @@ -173,7 +177,18 @@ public class OsmAndProtocolDecoder extends BaseHttpProtocolDecoder { } if (position.getDeviceId() != 0) { - sendResponse(channel, HttpResponseStatus.OK); + String response = null; + CommandsManager commandsManager = Context.getCommandsManager(); + if (commandsManager != null) { + for (Command command : commandsManager.readQueuedCommands(position.getDeviceId(), 1)) { + response = command.getString(Command.KEY_DATA); + } + } + if (response != null) { + sendResponse(channel, HttpResponseStatus.OK, Unpooled.copiedBuffer(response, StandardCharsets.UTF_8)); + } else { + sendResponse(channel, HttpResponseStatus.OK); + } return position; } else { sendResponse(channel, HttpResponseStatus.BAD_REQUEST); @@ -181,4 +196,8 @@ public class OsmAndProtocolDecoder extends BaseHttpProtocolDecoder { } } + @Override + protected void sendQueuedCommands(Channel channel, SocketAddress remoteAddress, long deviceId) { + } + } -- cgit v1.2.3 From 2816e5ed49e6d237f2a4e48a98cd4a5f1a893246 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 23 Mar 2020 20:59:09 -0700 Subject: Support position for single device --- src/main/java/org/traccar/api/resource/PositionResource.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java index c031b842f..67aa6dd32 100644 --- a/src/main/java/org/traccar/api/resource/PositionResource.java +++ b/src/main/java/org/traccar/api/resource/PositionResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2020 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. @@ -34,6 +34,7 @@ import javax.ws.rs.core.Response; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; @Path("positions") @@ -63,8 +64,12 @@ public class PositionResource extends BaseResource { return Context.getDeviceManager().getInitialState(getUserId()); } else { Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - return Context.getDataManager().getPositions( - deviceId, DateUtil.parseDate(from), DateUtil.parseDate(to)); + if (from != null && to != null) { + return Context.getDataManager().getPositions( + deviceId, DateUtil.parseDate(from), DateUtil.parseDate(to)); + } else { + return Collections.singleton(Context.getDeviceManager().getLastPosition(deviceId)); + } } } -- cgit v1.2.3 From f3d465abe7f255ec44e976caade642e4c2fd7598 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 23 Mar 2020 21:13:35 -0700 Subject: Support null values --- .../traccar/protocol/SigfoxProtocolDecoder.java | 70 +++++++++++++++------- .../protocol/SigfoxProtocolDecoderTest.java | 6 ++ 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java index c2c3d0fc3..5fc81085b 100644 --- a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java @@ -48,6 +48,31 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { super(protocol); } + private boolean jsonContains(JsonObject json, String key) { + if (json.containsKey(key)) { + JsonValue value = json.get(key); + if (value.getValueType() == JsonValue.ValueType.STRING) { + return !((JsonString) value).getString().equals("null"); + + } else { + return true; + } + } + return false; + } + + private boolean getJsonBoolean(JsonObject json, String key) { + JsonValue value = json.get(key); + if (value != null) { + if (value.getValueType() == JsonValue.ValueType.STRING) { + return Boolean.parseBoolean(((JsonString) value).getString()); + } else { + return value.getValueType() == JsonValue.ValueType.TRUE; + } + } + return false; + } + private int getJsonInt(JsonObject json, String key) { JsonValue value = json.get(key); if (value != null) { @@ -99,46 +124,36 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - if (json.containsKey("time")) { + if (jsonContains(json, "time")) { position.setTime(new Date(getJsonInt(json, "time") * 1000L)); - } else if (json.containsKey("positionTime")) { + } else if (jsonContains(json, "positionTime")) { position.setTime(new Date(getJsonInt(json, "positionTime") * 1000L)); } else { position.setTime(new Date()); } - if (json.containsKey("lastSeen")) { + if (jsonContains(json, "lastSeen")) { position.setDeviceTime(new Date(getJsonInt(json, "lastSeen") * 1000L)); } - if (json.containsKey("location") - || json.containsKey("lat") && json.containsKey("lng") && !json.containsKey("data") - || json.containsKey("latitude") && json.containsKey("longitude") && !json.containsKey("data")) { + if (jsonContains(json, "location") + || jsonContains(json, "lat") && jsonContains(json, "lng") && !jsonContains(json, "data") + || jsonContains(json, "latitude") && jsonContains(json, "longitude") && !jsonContains(json, "data")) { JsonObject location; - if (json.containsKey("location")) { + if (jsonContains(json, "location")) { location = json.getJsonObject("location"); } else { location = json; } position.setValid(true); - position.setLatitude(getJsonDouble(location, location.containsKey("lat") ? "lat" : "latitude")); - position.setLongitude(getJsonDouble(location, location.containsKey("lng") ? "lng" : "longitude")); - - if (location.containsKey("moving")) { - position.set(Position.KEY_MOTION, location.getBoolean("moving")); - } - if (location.containsKey("magStatus")) { - position.set(Position.KEY_BLOCKED, location.getBoolean("magStatus")); - } - if (location.containsKey("temperature")) { - position.set(Position.KEY_DEVICE_TEMP, location.getJsonNumber("temperature").doubleValue()); - } + position.setLatitude(getJsonDouble(location, jsonContains(location, "lat") ? "lat" : "latitude")); + position.setLongitude(getJsonDouble(location, jsonContains(location, "lng") ? "lng" : "longitude")); - } else { + } else if (jsonContains(json, "data") || jsonContains(json, "payload")) { - String data = json.getString(json.containsKey("data") ? "data" : "payload"); + String data = json.getString(jsonContains(json, "data") ? "data" : "payload"); ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(data)); try { int event = buf.readUnsignedByte(); @@ -229,10 +244,19 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { getLastLocation(position, position.getDeviceTime()); } - if (json.containsKey("rssi")) { + if (jsonContains(json, "moving")) { + position.set(Position.KEY_MOTION, getJsonBoolean(json, "moving")); + } + if (jsonContains(json, "magStatus")) { + position.set(Position.KEY_BLOCKED, getJsonBoolean(json, "magStatus")); + } + if (jsonContains(json, "temperature")) { + position.set(Position.KEY_DEVICE_TEMP, getJsonDouble(json, "temperature")); + } + if (jsonContains(json, "rssi")) { position.set(Position.KEY_RSSI, getJsonDouble(json, "rssi")); } - if (json.containsKey("seqNumber")) { + if (jsonContains(json, "seqNumber")) { position.set(Position.KEY_INDEX, getJsonInt(json, "seqNumber")); } diff --git a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java index 2bf6276b3..0ee34a4fc 100644 --- a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java @@ -12,6 +12,12 @@ public class SigfoxProtocolDecoderTest extends ProtocolTest { SigfoxProtocolDecoder decoder = new SigfoxProtocolDecoder(null); + verifyAttributes(decoder, request(HttpMethod.POST, "/", + buffer("{\"messageType\":\"accelerometer\",\"deviceId\":\"testdev001\",\"snr\":\"1234\",\"rssi\":\"-120.00\",\"station\":\"5678\",\"seqNum\":\"9123\",\"newPosition\":false,\"latitude\":\"null\",\"longitude\":\"null\",\"positionTime\":\"null\",\"moving\":true,\"magChange\":\"true\",\"magStatus\":\"true\",\"temperature\":\"7.5\",\"battery\":\"null\",\"batteryPercentage\":\"null\",\"lastSeen\":\"1582560425\",\"fwVersion\":\"null\",\"dlConfig\":\"null\",\"recievedPayload\":\"cb020051\"}"))); + + verifyAttributes(decoder, request(HttpMethod.POST, "/", + buffer("{\"messageType\":\"downlinkAcknowledgement\",\"deviceId\":\"testdev002\",\"snr\":\"1234\",\"rssi\":\"-120.00\",\"station\":\"5678\",\"seqNum\":\"9123\",\"newPosition\":false,\"latitude\":\"null\",\"longitude\":\"null\",\"positionTime\":\"null\",\"moving\":false,\"magChange\":\"true\",\"magStatus\":\"true\",\"temperature\":\"8.5\",\"battery\":\"3.6\",\"batteryPercentage\":\"100\",\"lastSeen\":\"1582560425\",\"fwVersion\":\"1.15\",\"dlConfig\":\"808c180202140216\",\"recievedPayload\":\"cf808c180202140216b4010f\"}"))); + verifyPosition(decoder, request(HttpMethod.POST, "/", buffer("{\"deviceId\":\"3377BC\",\"snr\":\"16.46\",\"rssi\":\"-123.00\",\"station\":\"-123.00\",\"seqNum\":\"3042\",\"newPosition\":true,\"latitude\":51.9189749,\"longitude\":-8.3979322,\"positionTime\":\"1582801850\",\"moving\":false,\"magChange\":false,\"magStatus\":false,\"temperature\":-2,\"battery\":\"null\",\"batteryPercentage\":\"null\",\"lastSeen\":\"1582801850\",\"fwVersion\":\"null\",\"dlConfig\":\"null\",\"recievedPayload\":\"09495a9085f5c94c\"}"))); -- cgit v1.2.3