aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/org/traccar/BaseProtocolDecoder.java9
-rw-r--r--src/org/traccar/Context.java32
-rw-r--r--src/org/traccar/events/IgnitionEventHandler.java5
-rw-r--r--src/org/traccar/geocoder/GeocodeFarmGeocoder.java13
-rw-r--r--src/org/traccar/geocoder/GoogleGeocoder.java19
-rw-r--r--src/org/traccar/geocoder/NominatimGeocoder.java16
-rw-r--r--src/org/traccar/model/Position.java2
-rw-r--r--src/org/traccar/protocol/At2000ProtocolDecoder.java4
-rw-r--r--src/org/traccar/protocol/CellocatorProtocol.java7
-rw-r--r--src/org/traccar/protocol/CellocatorProtocolDecoder.java18
-rw-r--r--src/org/traccar/protocol/CellocatorProtocolEncoder.java72
-rw-r--r--src/org/traccar/protocol/GalileoProtocolDecoder.java13
-rw-r--r--src/org/traccar/protocol/Gl200ProtocolDecoder.java20
-rw-r--r--src/org/traccar/protocol/H02FrameDecoder.java9
-rw-r--r--src/org/traccar/protocol/H02ProtocolDecoder.java14
-rw-r--r--src/org/traccar/protocol/TaipProtocolDecoder.java33
-rw-r--r--src/org/traccar/protocol/TeltonikaProtocolDecoder.java9
-rw-r--r--src/org/traccar/protocol/TmgProtocolDecoder.java31
-rw-r--r--swagger.json280
-rw-r--r--test/org/traccar/FilterHandlerTest.java10
-rw-r--r--test/org/traccar/ProtocolTest.java4
-rw-r--r--test/org/traccar/geocoder/GeocoderTest.java18
-rw-r--r--test/org/traccar/protocol/At2000ProtocolDecoderTest.java8
-rw-r--r--test/org/traccar/protocol/CellocatorProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/CellocatorProtocolEncoderTest.java26
-rw-r--r--test/org/traccar/protocol/GalileoFrameDecoderTest.java26
-rw-r--r--test/org/traccar/protocol/GalileoProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/Gl200ProtocolDecoderTest.java9
-rw-r--r--test/org/traccar/protocol/H02FrameDecoderTest.java4
-rw-r--r--test/org/traccar/protocol/H02ProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/TaipProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/TmgProtocolDecoderTest.java15
-rwxr-xr-xtools/swagger2html.py10
34 files changed, 659 insertions, 101 deletions
diff --git a/src/org/traccar/BaseProtocolDecoder.java b/src/org/traccar/BaseProtocolDecoder.java
index 8748a9be6..e5fa76a47 100644
--- a/src/org/traccar/BaseProtocolDecoder.java
+++ b/src/org/traccar/BaseProtocolDecoder.java
@@ -46,7 +46,16 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
try {
Context.getDeviceManager().addDevice(device);
+
Log.info("Automatically registered device " + uniqueId);
+
+ if (defaultGroupId != 0) {
+ Context.getPermissionsManager().refreshPermissions();
+ if (Context.getGeofenceManager() != null) {
+ Context.getGeofenceManager().refresh();
+ }
+ }
+
return device.getId();
} catch (SQLException e) {
Log.warning(e);
diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java
index cd6820778..27e61d32d 100644
--- a/src/org/traccar/Context.java
+++ b/src/org/traccar/Context.java
@@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.SerializationFeature;
import com.ning.http.client.AsyncHttpClient;
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.Properties;
import org.apache.velocity.app.VelocityEngine;
@@ -208,15 +209,12 @@ public final class Context {
String type = config.getString("geocoder.type", "google");
String url = config.getString("geocoder.url");
String key = config.getString("geocoder.key");
+ String language = config.getString("geocoder.language");
int cacheSize = config.getInteger("geocoder.cacheSize");
switch (type) {
case "nominatim":
- if (key != null) {
- geocoder = new NominatimGeocoder(url, key, cacheSize);
- } else {
- geocoder = new NominatimGeocoder(url, cacheSize);
- }
+ geocoder = new NominatimGeocoder(url, key, cacheSize);
break;
case "gisgraphy":
geocoder = new GisgraphyGeocoder(url, cacheSize);
@@ -234,17 +232,10 @@ public final class Context {
geocoder = new FactualGeocoder(url, key, cacheSize);
break;
case "geocodefarm":
- if (key != null) {
- geocoder = new GeocodeFarmGeocoder(key, cacheSize);
- } else {
- geocoder = new GeocodeFarmGeocoder(cacheSize);
- }
+ geocoder = new GeocodeFarmGeocoder(key, cacheSize);
+ break;
default:
- if (key != null) {
- geocoder = new GoogleGeocoder(key, cacheSize);
- } else {
- geocoder = new GoogleGeocoder(cacheSize);
- }
+ geocoder = new GoogleGeocoder(key, language, cacheSize);
break;
}
}
@@ -291,9 +282,14 @@ public final class Context {
velocityProperties.setProperty("runtime.log.logsystem.class",
"org.apache.velocity.runtime.log.NullLogChute");
- String address = config.getString("web.address", InetAddress.getLocalHost().getHostAddress());
- int port = config.getInteger("web.port", 8082);
- String webUrl = URIUtil.newURI("http", address, port, "", "");
+ String address;
+ try {
+ address = config.getString("web.address", InetAddress.getLocalHost().getHostAddress());
+ } catch (UnknownHostException e) {
+ address = "localhost";
+ }
+
+ String webUrl = URIUtil.newURI("http", address, config.getInteger("web.port", 8082), "", "");
webUrl = Context.getConfig().getString("web.url", webUrl);
velocityProperties.setProperty("web.url", webUrl);
diff --git a/src/org/traccar/events/IgnitionEventHandler.java b/src/org/traccar/events/IgnitionEventHandler.java
index 187b7ce73..c628cc107 100644
--- a/src/org/traccar/events/IgnitionEventHandler.java
+++ b/src/org/traccar/events/IgnitionEventHandler.java
@@ -30,10 +30,7 @@ public class IgnitionEventHandler extends BaseEventHandler {
@Override
protected Collection<Event> analyzePosition(Position position) {
Device device = Context.getIdentityManager().getDeviceById(position.getDeviceId());
- if (device == null) {
- return null;
- }
- if (!Context.getIdentityManager().isLatestPosition(position) || !position.getValid()) {
+ if (device == null || !Context.getIdentityManager().isLatestPosition(position)) {
return null;
}
diff --git a/src/org/traccar/geocoder/GeocodeFarmGeocoder.java b/src/org/traccar/geocoder/GeocodeFarmGeocoder.java
index 585095606..db23aab79 100644
--- a/src/org/traccar/geocoder/GeocodeFarmGeocoder.java
+++ b/src/org/traccar/geocoder/GeocodeFarmGeocoder.java
@@ -19,14 +19,15 @@ import javax.json.JsonObject;
public class GeocodeFarmGeocoder extends JsonGeocoder {
- private static final String URL = "https://www.geocode.farm/v3/json/reverse/";
-
- public GeocodeFarmGeocoder(int cacheSize) {
- super(URL + "?lat=%f&lon=%f&country=us&lang=en&count=1", cacheSize);
+ private static String formatUrl(String key) {
+ String url = "https://www.geocode.farm/v3/json/reverse/";
+ if (key != null) {
+ url += "&key=" + key;
+ }
+ return url;
}
-
public GeocodeFarmGeocoder(String key, int cacheSize) {
- super(URL + "?lat=%f&lon=%f&country=us&lang=en&count=1&key=" + key, cacheSize);
+ super(formatUrl(key), cacheSize);
}
@Override
diff --git a/src/org/traccar/geocoder/GoogleGeocoder.java b/src/org/traccar/geocoder/GoogleGeocoder.java
index 0506e701a..b38870c8f 100644
--- a/src/org/traccar/geocoder/GoogleGeocoder.java
+++ b/src/org/traccar/geocoder/GoogleGeocoder.java
@@ -21,16 +21,19 @@ import javax.json.JsonString;
public class GoogleGeocoder extends JsonGeocoder {
- public GoogleGeocoder() {
- this(0);
- }
-
- public GoogleGeocoder(int cacheSize) {
- super("http://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f", cacheSize);
+ private static String formatUrl(String key, String language) {
+ String url = "https://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f";
+ if (key != null) {
+ url += "&key=" + key;
+ }
+ if (language != null) {
+ url += "&language=" + language;
+ }
+ return url;
}
- public GoogleGeocoder(String key, int cacheSize) {
- super("https://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f&key=" + key, cacheSize);
+ public GoogleGeocoder(String key, String language, int cacheSize) {
+ super(formatUrl(key, language), cacheSize);
}
@Override
diff --git a/src/org/traccar/geocoder/NominatimGeocoder.java b/src/org/traccar/geocoder/NominatimGeocoder.java
index b0ee39c6a..c10a1414e 100644
--- a/src/org/traccar/geocoder/NominatimGeocoder.java
+++ b/src/org/traccar/geocoder/NominatimGeocoder.java
@@ -19,16 +19,18 @@ import javax.json.JsonObject;
public class NominatimGeocoder extends JsonGeocoder {
- public NominatimGeocoder() {
- this("http://nominatim.openstreetmap.org/reverse", 0);
- }
-
- public NominatimGeocoder(String url, int cacheSize) {
- super(url + "?format=json&lat=%f&lon=%f&zoom=18&addressdetails=1", cacheSize);
+ private static String formatUrl(String url, String key) {
+ if (url == null) {
+ url = "http://nominatim.openstreetmap.org/reverse";
+ }
+ if (key != null) {
+ url += "&key=" + key;
+ }
+ return url;
}
public NominatimGeocoder(String url, String key, int cacheSize) {
- super(url + "?format=json&lat=%f&lon=%f&zoom=18&addressdetails=1&key=" + key, cacheSize);
+ super(formatUrl(url, key), cacheSize);
}
@Override
diff --git a/src/org/traccar/model/Position.java b/src/org/traccar/model/Position.java
index 288901430..350524f32 100644
--- a/src/org/traccar/model/Position.java
+++ b/src/org/traccar/model/Position.java
@@ -76,6 +76,7 @@ public class Position extends Message {
public static final String ALARM_LOW_SPEED = "lowspeed";
public static final String ALARM_OVERSPEED = "overspeed";
public static final String ALARM_FALL_DOWN = "fallDown";
+ public static final String ALARM_LOW_POWER = "lowPower";
public static final String ALARM_LOW_BATTERY = "lowBattery";
public static final String ALARM_FAULT = "fault";
public static final String ALARM_POWER_OFF = "powerOff";
@@ -98,6 +99,7 @@ public class Position extends Message {
public static final String ALARM_BONNET = "bonnet";
public static final String ALARM_FOOT_BRAKE = "footBrake";
public static final String ALARM_OIL_LEAK = "oilLeak";
+ public static final String ALARM_TAMPERING = "tampering";
private String protocol;
diff --git a/src/org/traccar/protocol/At2000ProtocolDecoder.java b/src/org/traccar/protocol/At2000ProtocolDecoder.java
index dc799054d..182066629 100644
--- a/src/org/traccar/protocol/At2000ProtocolDecoder.java
+++ b/src/org/traccar/protocol/At2000ProtocolDecoder.java
@@ -102,6 +102,10 @@ public class At2000ProtocolDecoder extends BaseProtocolDecoder {
return null;
}
+ if (buf.capacity() <= BLOCK_LENGTH) {
+ return null; // empty message
+ }
+
byte[] data = new byte[buf.capacity() - BLOCK_LENGTH];
buf.readBytes(data);
buf = ChannelBuffers.wrappedBuffer(ByteOrder.LITTLE_ENDIAN, cipher.update(data));
diff --git a/src/org/traccar/protocol/CellocatorProtocol.java b/src/org/traccar/protocol/CellocatorProtocol.java
index bfaf03692..7c8510204 100644
--- a/src/org/traccar/protocol/CellocatorProtocol.java
+++ b/src/org/traccar/protocol/CellocatorProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2017 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,6 +20,7 @@ import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.traccar.BaseProtocol;
import org.traccar.TrackerServer;
+import org.traccar.model.Command;
import java.nio.ByteOrder;
import java.util.List;
@@ -28,6 +29,8 @@ public class CellocatorProtocol extends BaseProtocol {
public CellocatorProtocol() {
super("cellocator");
+ setSupportedCommands(
+ Command.TYPE_OUTPUT_CONTROL);
}
@Override
@@ -36,6 +39,7 @@ public class CellocatorProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CellocatorFrameDecoder());
+ pipeline.addLast("objectEncoder", new CellocatorProtocolEncoder());
pipeline.addLast("objectDecoder", new CellocatorProtocolDecoder(CellocatorProtocol.this));
}
};
@@ -45,6 +49,7 @@ public class CellocatorProtocol extends BaseProtocol {
server = new TrackerServer(new ConnectionlessBootstrap(), getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("objectEncoder", new CellocatorProtocolEncoder());
pipeline.addLast("objectDecoder", new CellocatorProtocolDecoder(CellocatorProtocol.this));
}
};
diff --git a/src/org/traccar/protocol/CellocatorProtocolDecoder.java b/src/org/traccar/protocol/CellocatorProtocolDecoder.java
index 14325e619..7df8cad8a 100644
--- a/src/org/traccar/protocol/CellocatorProtocolDecoder.java
+++ b/src/org/traccar/protocol/CellocatorProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2017 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,6 +68,19 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder {
}
}
+ private String decodeAlarm(short reason) {
+ switch (reason) {
+ case 70:
+ return Position.ALARM_SOS;
+ case 80:
+ return Position.ALARM_POWER_CUT;
+ case 81:
+ return Position.ALARM_LOW_POWER;
+ default:
+ return null;
+ }
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -106,7 +119,8 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder {
operator += buf.readUnsignedByte();
buf.readUnsignedByte(); // reason data
- buf.readUnsignedByte(); // reason
+ position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
+
buf.readUnsignedByte(); // mode
buf.readUnsignedInt(); // IO
diff --git a/src/org/traccar/protocol/CellocatorProtocolEncoder.java b/src/org/traccar/protocol/CellocatorProtocolEncoder.java
new file mode 100644
index 000000000..bb143d349
--- /dev/null
+++ b/src/org/traccar/protocol/CellocatorProtocolEncoder.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.traccar.BaseProtocolEncoder;
+import org.traccar.helper.Log;
+import org.traccar.model.Command;
+
+import java.nio.ByteOrder;
+
+public class CellocatorProtocolEncoder extends BaseProtocolEncoder {
+
+ private ChannelBuffer encodeContent(long deviceId, int command, int data1, int data2) {
+
+ ChannelBuffer buf = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0);
+ buf.writeByte('M');
+ buf.writeByte('C');
+ buf.writeByte('G');
+ buf.writeByte('P');
+ buf.writeByte(0);
+ buf.writeInt(Integer.parseInt(getUniqueId(deviceId)));
+ buf.writeByte(0); // command numerator
+ buf.writeInt(0); // authentication code
+ buf.writeByte(command);
+ buf.writeByte(command);
+ buf.writeByte(data1);
+ buf.writeByte(data1);
+ buf.writeByte(data2);
+ buf.writeByte(data2);
+ buf.writeInt(0); // command specific data
+
+ byte checksum = 0;
+ for (int i = 4; i < buf.writerIndex(); i++) {
+ checksum += buf.getByte(i);
+ }
+ buf.writeByte(checksum);
+
+ return buf;
+ }
+
+ @Override
+ protected Object encodeCommand(Command command) {
+
+ switch (command.getType()) {
+ case Command.TYPE_OUTPUT_CONTROL:
+ int data = Integer.parseInt(command.getString(Command.KEY_DATA)) << 4
+ + command.getInteger(Command.KEY_INDEX);
+ return encodeContent(command.getDeviceId(), 0x03, data, 0);
+ default:
+ Log.warning(new UnsupportedOperationException(command.getType()));
+ break;
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/protocol/GalileoProtocolDecoder.java b/src/org/traccar/protocol/GalileoProtocolDecoder.java
index 68063c5c3..c9aae8e96 100644
--- a/src/org/traccar/protocol/GalileoProtocolDecoder.java
+++ b/src/org/traccar/protocol/GalileoProtocolDecoder.java
@@ -55,6 +55,7 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
private static final int TAG_ADC1 = 0x51;
private static final int TAG_ADC2 = 0x52;
private static final int TAG_ADC3 = 0x53;
+ private static final int TAG_ARRAY = 0xea;
private static final Map<Integer, Integer> TAG_LENGTH_MAP = new HashMap<>();
@@ -81,7 +82,7 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
0x20, 0x33, 0x44, 0x90, 0xc0, 0xc2, 0xc3, 0xd3,
0xd4, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xf0, 0xf9,
0x5a, 0x47, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
- 0xf7, 0xf8
+ 0xf7, 0xf8, 0xe2, 0xe9
};
for (int i : l1) {
TAG_LENGTH_MAP.put(i, 1);
@@ -102,7 +103,11 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
}
private static int getTagLength(int tag) {
- return TAG_LENGTH_MAP.get(tag);
+ Integer length = TAG_LENGTH_MAP.get(tag);
+ if (length == null) {
+ throw new IllegalArgumentException("Unknown tag: " + tag);
+ }
+ return length;
}
private void sendReply(Channel channel, int checksum) {
@@ -207,6 +212,10 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort());
break;
+ case TAG_ARRAY:
+ buf.skipBytes(buf.readUnsignedByte());
+ break;
+
default:
buf.skipBytes(getTagLength(tag));
break;
diff --git a/src/org/traccar/protocol/Gl200ProtocolDecoder.java b/src/org/traccar/protocol/Gl200ProtocolDecoder.java
index 59f013313..ef434b779 100644
--- a/src/org/traccar/protocol/Gl200ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gl200ProtocolDecoder.java
@@ -107,7 +107,7 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
.compile();
private static final Pattern PATTERN_LOCATION = new PatternBuilder()
- .number("(?:d{1,2})?,") // gps accuracy
+ .number("(d{1,2})?,") // hdop
.number("(d{1,3}.d)?,") // speed
.number("(d{1,3})?,") // course
.number("(-?d{1,5}.d)?,") // altitude
@@ -275,6 +275,7 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
.number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
.number("(d{15}|x{14}),") // imei
.any()
+ .number("(d{1,2})?,") // hdop
.number("(d{1,3}.d)?,") // speed
.number("(d{1,3})?,") // course
.number("(-?d{1,5}.d)?,") // altitude
@@ -399,6 +400,10 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
}
private void decodeLocation(Position position, Parser parser) {
+ int hdop = parser.nextInt();
+ position.setValid(hdop > 0);
+ position.set(Position.KEY_HDOP, hdop);
+
position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
position.setCourse(parser.nextDouble());
position.setAltitude(parser.nextDouble());
@@ -451,11 +456,11 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
position.set("dtcsCodes", parser.next());
position.set(Position.KEY_THROTTLE, parser.next());
position.set(Position.KEY_FUEL, parser.next());
- position.set(Position.KEY_OBD_ODOMETER, parser.next());
+ position.set(Position.KEY_OBD_ODOMETER, parser.nextInt() * 1000);
decodeLocation(position, parser);
- position.set(Position.KEY_ODOMETER, parser.next());
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
if (parser.hasNext(6)) {
DateBuilder dateBuilder = new DateBuilder()
@@ -510,7 +515,7 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
position.set(Position.KEY_BATTERY, parser.next());
- position.set(Position.KEY_ODOMETER, parser.next());
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
position.set(Position.KEY_HOURS, parser.next());
position.set(Position.PREFIX_ADC + 1, parser.next());
position.set(Position.PREFIX_ADC + 2, parser.next());
@@ -666,7 +671,7 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
decodeLocation(position, parser);
- position.set(Position.KEY_ODOMETER, parser.next());
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
position.set(Position.KEY_BATTERY, parser.next());
position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
@@ -703,12 +708,15 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
position.setProtocol(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
+ int hdop = parser.nextInt();
+ position.setValid(hdop > 0);
+ position.set(Position.KEY_HDOP, hdop);
+
position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
position.setCourse(parser.nextDouble());
position.setAltitude(parser.nextDouble());
if (parser.hasNext(2)) {
- position.setValid(true);
position.setLongitude(parser.nextDouble());
position.setLatitude(parser.nextDouble());
} else {
diff --git a/src/org/traccar/protocol/H02FrameDecoder.java b/src/org/traccar/protocol/H02FrameDecoder.java
index f1d305ab6..391fccc87 100644
--- a/src/org/traccar/protocol/H02FrameDecoder.java
+++ b/src/org/traccar/protocol/H02FrameDecoder.java
@@ -50,7 +50,12 @@ public class H02FrameDecoder extends FrameDecoder {
// Return text message
int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '#');
if (index != -1) {
- return buf.readBytes(index + 1 - buf.readerIndex());
+ ChannelBuffer result = buf.readBytes(index + 1 - buf.readerIndex());
+ while (buf.readable()
+ && (buf.getByte(buf.readerIndex()) == '\r' || buf.getByte(buf.readerIndex()) == '\n')) {
+ buf.readByte(); // skip new line
+ }
+ return result;
}
break;
@@ -81,7 +86,7 @@ public class H02FrameDecoder extends FrameDecoder {
default:
- throw new IllegalArgumentException();
+ return null;
}
return null;
diff --git a/src/org/traccar/protocol/H02ProtocolDecoder.java b/src/org/traccar/protocol/H02ProtocolDecoder.java
index 37f6294be..a717ddc4d 100644
--- a/src/org/traccar/protocol/H02ProtocolDecoder.java
+++ b/src/org/traccar/protocol/H02ProtocolDecoder.java
@@ -75,7 +75,7 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED);
}
- position.set(Position.KEY_IGNITION, !BitUtil.check(status, 10));
+ position.set(Position.KEY_IGNITION, BitUtil.check(status, 10));
position.set(Position.KEY_STATUS, status);
}
@@ -165,16 +165,10 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
.expression("([EW]),")
.number("(d+.?d*),") // speed
.number("(d+.?d*)?,") // course
- .number("(?:(dd)(dd)(dd))?,") // date (ddmmyy)
- .any()
- .number("(x{8})") // status
- .groupBegin()
- .number(", *(x+),") // mcc
- .number(" *(x+),") // mnc
- .number(" *(x+),") // lac
- .number(" *(x+)") // cid
- .groupEnd("?")
+ .number("(?:(dd)(dd)(dd))?") // date (ddmmyy)
.any()
+ .number(",(x{8})") // status
+ .expression("(?:#|,.*)")
.compile();
private static final Pattern PATTERN_NBR = new PatternBuilder()
diff --git a/src/org/traccar/protocol/TaipProtocolDecoder.java b/src/org/traccar/protocol/TaipProtocolDecoder.java
index 7927c28e6..c53538223 100644
--- a/src/org/traccar/protocol/TaipProtocolDecoder.java
+++ b/src/org/traccar/protocol/TaipProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2015 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2017 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.
@@ -48,7 +48,8 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
.groupEnd("?")
.number("(d{5})") // seconds
.or()
- .text("RGP") // type
+ .expression("(?:RGP|RCQ|RBR)") // type
+ .number("(?:dd)?")
.number("(dd)(dd)(dd)") // date
.number("(dd)(dd)(dd)") // time
.groupEnd()
@@ -56,6 +57,13 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
.number("([-+]ddd)(d{5})") // longitude
.number("(ddd)") // speed
.number("(ddd)") // course
+ .groupBegin()
+ .number("(xx)") // input
+ .number("(xx)") // satellites
+ .number("(ddd)") // battery
+ .number("(x{8})") // odometer
+ .number("[01]") // gps power
+ .groupEnd("?")
.number("(d)") // fix mode
.any()
.compile();
@@ -93,15 +101,10 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position();
position.setProtocol(getProtocolName());
- String week = parser.next();
- String day = parser.next();
- String seconds = parser.next();
- if (seconds != null) {
- if (week != null && day != null) {
- position.setTime(getTime(Integer.parseInt(week), Integer.parseInt(day), Integer.parseInt(seconds)));
- } else {
- position.setTime(getTime(Integer.parseInt(seconds)));
- }
+ if (parser.hasNext(2)) {
+ position.setTime(getTime(parser.nextInt(), parser.nextInt(), parser.nextInt()));
+ } else if (parser.hasNext()) {
+ position.setTime(getTime(parser.nextInt()));
}
if (parser.hasNext(6)) {
@@ -115,6 +118,14 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_DEG));
position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble()));
position.setCourse(parser.nextDouble());
+
+ if (parser.hasNext(4)) {
+ position.set(Position.KEY_INPUT, parser.nextInt(16));
+ position.set(Position.KEY_SATELLITES, parser.nextInt(16));
+ position.set(Position.KEY_BATTERY, parser.nextInt());
+ position.set(Position.KEY_ODOMETER, parser.nextLong(16));
+ }
+
position.setValid(parser.nextInt() != 0);
String[] attributes = null;
diff --git a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
index e647a33a0..9c1e0a2ff 100644
--- a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
+++ b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
@@ -73,6 +73,12 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
private void decodeParameter(Position position, int id, ChannelBuffer buf, int length) {
switch (id) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ position.set("di" + id, buf.readUnsignedByte());
+ break;
case 9:
position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort());
break;
@@ -82,6 +88,9 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
case 67:
position.set(Position.KEY_BATTERY, buf.readUnsignedShort() + "mV");
break;
+ case 70:
+ position.set("pcbTemp", (length == 4 ? buf.readInt() : buf.readShort()) * 0.1);
+ break;
case 72:
position.set(Position.PREFIX_TEMP + 1, buf.readInt() * 0.1);
break;
diff --git a/src/org/traccar/protocol/TmgProtocolDecoder.java b/src/org/traccar/protocol/TmgProtocolDecoder.java
index 9fa8759a0..3b73a1516 100644
--- a/src/org/traccar/protocol/TmgProtocolDecoder.java
+++ b/src/org/traccar/protocol/TmgProtocolDecoder.java
@@ -35,7 +35,7 @@ public class TmgProtocolDecoder extends BaseProtocolDecoder {
private static final Pattern PATTERN = new PatternBuilder()
.text("$")
- .expression("...,") // type
+ .expression("(...),") // type
.expression("[LH],") // history
.number("(d+),") // imei
.number("(dd)(dd)(dddd),") // date
@@ -53,7 +53,7 @@ public class TmgProtocolDecoder extends BaseProtocolDecoder {
.number("(d+),") // visible satellites
.number("([^,]*),") // operator
.number("(d+),") // rssi
- .number("x+,") // cid
+ .number("[^,]*,") // cid
.expression("([01]),") // ignition
.number("(d+.?d*),") // battery
.number("(d+.?d*),") // power
@@ -72,6 +72,8 @@ public class TmgProtocolDecoder extends BaseProtocolDecoder {
return null;
}
+ String type = parser.next();
+
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
if (deviceSession == null) {
return null;
@@ -81,6 +83,31 @@ public class TmgProtocolDecoder extends BaseProtocolDecoder {
position.setProtocol(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
+ switch (type) {
+ case "rmv":
+ position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT);
+ break;
+ case "ebl":
+ position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER);
+ break;
+ case "ibl":
+ position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
+ break;
+ case "tmp":
+ case "smt":
+ case "btt":
+ position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING);
+ break;
+ case "ion":
+ position.set(Position.KEY_IGNITION, true);
+ break;
+ case "iof":
+ position.set(Position.KEY_IGNITION, false);
+ break;
+ default:
+ break;
+ }
+
DateBuilder dateBuilder = new DateBuilder()
.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt())
.setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
diff --git a/swagger.json b/swagger.json
index 0f298f161..0857138e2 100644
--- a/swagger.json
+++ b/swagger.json
@@ -1,7 +1,7 @@
{
"swagger": "2.0",
"info": {
- "version": "3.9",
+ "version": "3.10",
"title": "traccar"
},
"host": "demo.traccar.org",
@@ -384,10 +384,82 @@
}
}
},
+ "/permissions/calendars": {
+ "post": {
+ "summary": "Link a Calendar to a User",
+ "parameters": [
+ {
+ "$ref": "#/parameters/CalendarPermission"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/CalendarPermission"
+ }
+ }
+ }
+ },
+ "delete": {
+ "summary": "Remove a Calendar from a User",
+ "parameters": [
+ {
+ "$ref": "#/parameters/CalendarPermission"
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content"
+ }
+ }
+ }
+ },
+ "/permissions/users": {
+ "post": {
+ "summary": "Link a User to a manager User",
+ "parameters": [
+ {
+ "$ref": "#/parameters/UserPermission"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/UserPermission"
+ }
+ }
+ }
+ },
+ "delete": {
+ "summary": "Remove a User from a manager User",
+ "parameters": [
+ {
+ "$ref": "#/parameters/UserPermission"
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content"
+ }
+ }
+ }
+ },
"/positions": {
"get": {
"summary" : "Fetches a list of Positions",
"description" : "Without any params, it returns a list of last known positions for all the user's Devices. _from_ and _to_ fields are not required with _id_",
+ "consumes": [
+ "application/json",
+ "text/csv",
+ "application/gpx+xml"
+ ],
+ "produces": [
+ "application/json",
+ "text/csv",
+ "application/gpx+xml"
+ ],
"parameters": [
{
"name": "deviceId",
@@ -474,6 +546,14 @@
"consumes": [
"application/x-www-form-urlencoded"
],
+ "parameters": [
+ {
+ "name": "token",
+ "in": "query",
+ "required": false,
+ "type": "string"
+ }
+ ],
"responses": {
"200": {
"description": "OK",
@@ -534,6 +614,15 @@
"/users": {
"get": {
"summary": "Fetch a list of Users",
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "query",
+ "description": "Can only be used by admin or manager users",
+ "required": false,
+ "type": "string"
+ }
+ ],
"responses": {
"200": {
"description": "OK",
@@ -786,6 +875,14 @@
"get": {
"summary": "Fetch a list of Positions within the time period for the Devices or Groups",
"description": "At least one _deviceId_ or one _groupId_ must be passed",
+ "consumes": [
+ "application/json",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ ],
+ "produces": [
+ "application/json",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ ],
"parameters": [
{
"$ref": "#/parameters/deviceIdArray"
@@ -817,6 +914,14 @@
"get": {
"summary": "Fetch a list of Events within the time period for the Devices or Groups",
"description": "At least one _deviceId_ or one _groupId_ must be passed",
+ "consumes": [
+ "application/json",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ ],
+ "produces": [
+ "application/json",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ ],
"parameters": [
{
"$ref": "#/parameters/deviceIdArray"
@@ -857,6 +962,14 @@
"get": {
"summary": "Fetch a list of ReportSummary within the time period for the Devices or Groups",
"description": "At least one _deviceId_ or one _groupId_ must be passed",
+ "consumes": [
+ "application/json",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ ],
+ "produces": [
+ "application/json",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ ],
"parameters": [
{
"$ref": "#/parameters/deviceIdArray"
@@ -888,6 +1001,14 @@
"get": {
"summary": "Fetch a list of ReportTrips within the time period for the Devices or Groups",
"description": "At least one _deviceId_ or one _groupId_ must be passed",
+ "consumes": [
+ "application/json",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ ],
+ "produces": [
+ "application/json",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ ],
"parameters": [
{
"$ref": "#/parameters/deviceIdArray"
@@ -1010,6 +1131,81 @@
}
}
}
+ },
+ "/calendars": {
+ "get": {
+ "summary": "Fetch a list of Calendars",
+ "description": "Without params, it returns a list of Calendars the user has access to",
+ "parameters": [
+ {
+ "$ref": "#/parameters/all"
+ },
+ {
+ "$ref": "#/parameters/userId"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Calendar"
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "summary": "Create a Calendar",
+ "parameters": [
+ {
+ "$ref": "#/parameters/Calendar"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/Calendar"
+ }
+ }
+ }
+ }
+ },
+ "/calendars/{id}": {
+ "put": {
+ "summary": "Update a Calendar",
+ "parameters": [
+ {
+ "$ref": "#/parameters/entityId"
+ },
+ {
+ "$ref": "#/parameters/Calendar"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/Calendar"
+ }
+ }
+ }
+ },
+ "delete": {
+ "summary": "Delete a Calendar",
+ "parameters": [
+ {
+ "$ref": "#/parameters/entityId"
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content"
+ }
+ }
+ }
}
},
"definitions": {
@@ -1064,6 +1260,12 @@
"address": {
"type": "string"
},
+ "accuracy": {
+ "type": "number"
+ },
+ "network": {
+ "type": "string"
+ },
"attributes": {}
}
},
@@ -1122,6 +1324,12 @@
"deviceLimit": {
"type": "integer"
},
+ "userLimit": {
+ "type": "integer"
+ },
+ "deviceReadonly": {
+ "type": "boolean"
+ },
"token": {
"type": "string"
},
@@ -1279,6 +1487,26 @@
}
}
},
+ "CalendarPermission": {
+ "properties": {
+ "userId": {
+ "type": "integer"
+ },
+ "calendarId": {
+ "type": "integer"
+ }
+ }
+ },
+ "UserPermission": {
+ "properties": {
+ "userId": {
+ "type": "integer"
+ },
+ "managedUserId": {
+ "type": "integer"
+ }
+ }
+ },
"GroupGeofence": {
"properties": {
"groupId": {
@@ -1320,6 +1548,9 @@
"area": {
"type": "string"
},
+ "calendarId": {
+ "type": "integer"
+ },
"attributes": {}
}
},
@@ -1334,6 +1565,12 @@
"userId": {
"type": "integer"
},
+ "web": {
+ "type": "boolean"
+ },
+ "mail": {
+ "type": "boolean"
+ },
"attributes": {}
}
},
@@ -1490,6 +1727,21 @@
"description": "in meters"
}
}
+ },
+ "Calendar": {
+ "properties": {
+ "id": {
+ "type": "integer"
+ },
+ "name": {
+ "type": "string"
+ },
+ "data": {
+ "type": "string",
+ "description": "base64 encoded in iCalendar format"
+ },
+ "atributes": {}
+ }
}
},
"parameters": {
@@ -1502,7 +1754,7 @@
"all": {
"name": "all",
"in": "query",
- "description": "Can only be used by admin users to fetch all entities",
+ "description": "Can only be used by admins or managers to fetch all entities",
"type": "boolean"
},
"userId": {
@@ -1573,6 +1825,22 @@
"$ref": "#/definitions/GeofencePermission"
}
},
+ "CalendarPermission": {
+ "name": "body",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/CalendarPermission"
+ }
+ },
+ "UserPermission": {
+ "name": "body",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/UserPermission"
+ }
+ },
"User": {
"name": "body",
"in": "body",
@@ -1597,6 +1865,14 @@
"$ref": "#/definitions/AttributeAlias"
}
},
+ "Calendar": {
+ "name": "body",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/Calendar"
+ }
+ },
"deviceIdArray": {
"name": "deviceId",
"in": "query",
diff --git a/test/org/traccar/FilterHandlerTest.java b/test/org/traccar/FilterHandlerTest.java
index 11b4163a1..452592048 100644
--- a/test/org/traccar/FilterHandlerTest.java
+++ b/test/org/traccar/FilterHandlerTest.java
@@ -1,14 +1,14 @@
package org.traccar;
-import java.util.Date;
import org.junit.After;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import org.junit.Before;
import org.junit.Test;
-import org.traccar.database.IdentityManager;
import org.traccar.model.Position;
-import org.traccar.model.Device;
+
+import java.util.Date;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
public class FilterHandlerTest extends BaseTest {
diff --git a/test/org/traccar/ProtocolTest.java b/test/org/traccar/ProtocolTest.java
index 955e0b788..f4072ad24 100644
--- a/test/org/traccar/ProtocolTest.java
+++ b/test/org/traccar/ProtocolTest.java
@@ -6,10 +6,8 @@ import org.jboss.netty.handler.codec.http.DefaultHttpRequest;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpVersion;
import org.junit.Assert;
-import org.traccar.database.IdentityManager;
import org.traccar.model.CellTower;
import org.traccar.model.Command;
-import org.traccar.model.Device;
import org.traccar.model.Position;
import javax.xml.bind.DatatypeConverter;
@@ -147,7 +145,7 @@ public class ProtocolTest extends BaseTest {
} else {
Assert.assertNotNull(position.getFixTime());
- Assert.assertTrue("year > 2000", position.getFixTime().after(new Date(946684800000L)));
+ Assert.assertTrue("year > 1999", position.getFixTime().after(new Date(915148800000L)));
Assert.assertTrue("time < +25 hours",
position.getFixTime().getTime() < System.currentTimeMillis() + 25 * 3600000);
diff --git a/test/org/traccar/geocoder/GeocoderTest.java b/test/org/traccar/geocoder/GeocoderTest.java
index 012f8bacd..a5aecc8cf 100644
--- a/test/org/traccar/geocoder/GeocoderTest.java
+++ b/test/org/traccar/geocoder/GeocoderTest.java
@@ -1,17 +1,15 @@
package org.traccar.geocoder;
import org.junit.Assert;
+import org.junit.Ignore;
import org.junit.Test;
public class GeocoderTest {
- private boolean enable = false;
-
+ @Ignore
@Test
public void test() throws InterruptedException {
- if (enable) {
- testGeocodeFarm();
- }
+ testGoogle();
}
private String address;
@@ -31,9 +29,9 @@ public class GeocoderTest {
}
public void testGoogle() throws InterruptedException {
- Geocoder geocoder = new GoogleGeocoder();
+ Geocoder geocoder = new GoogleGeocoder(null, null, 0);
- geocoder.getAddress(new AddressFormat(), 37.4217550, -122.0846330, new Geocoder.ReverseGeocoderCallback() {
+ geocoder.getAddress(new AddressFormat(), 31.776797, 35.211489, new Geocoder.ReverseGeocoderCallback() {
@Override
public void onSuccess(String address) {
setAddress(address);
@@ -43,11 +41,11 @@ public class GeocoderTest {
public void onFailure(Throwable e) {
}
});
- Assert.assertEquals("1600 Amphitheatre Pkwy, Mountain View, CA, US", waitAddress());
+ Assert.assertEquals("1 Ibn Shaprut St, Jerusalem, Jerusalem District, IL", waitAddress());
}
public void testNominatim() throws InterruptedException {
- Geocoder geocoder = new NominatimGeocoder();
+ Geocoder geocoder = new NominatimGeocoder(null, null, 0);
geocoder.getAddress(new AddressFormat(), 40.7337807, -73.9974401, new Geocoder.ReverseGeocoderCallback() {
@Override
@@ -96,7 +94,7 @@ public class GeocoderTest {
}
public void testGeocodeFarm() throws InterruptedException {
- Geocoder geocoder = new GeocodeFarmGeocoder(0);
+ Geocoder geocoder = new GeocodeFarmGeocoder(null, 0);
geocoder.getAddress(new AddressFormat(), 34.116302, -118.051519, new Geocoder.ReverseGeocoderCallback() {
@Override
diff --git a/test/org/traccar/protocol/At2000ProtocolDecoderTest.java b/test/org/traccar/protocol/At2000ProtocolDecoderTest.java
index 596d2870d..0b1a9f471 100644
--- a/test/org/traccar/protocol/At2000ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/At2000ProtocolDecoderTest.java
@@ -19,6 +19,14 @@ public class At2000ProtocolDecoderTest extends ProtocolTest {
decoder = new At2000ProtocolDecoder(new At2000Protocol());
verifyNothing(decoder, binary(ByteOrder.LITTLE_ENDIAN,
+ "01012f00000000000000000000000000003335373435343037313632373539388b57ec3a6ec7e3310a1ceb0a70fd751b8f2e7be6df1d6dcd80129f66fff0ea1c"));
+
+ verifyNothing(decoder, binary(ByteOrder.LITTLE_ENDIAN,
+ "89000000000000000000000000000000"));
+
+ decoder = new At2000ProtocolDecoder(new At2000Protocol());
+
+ verifyNothing(decoder, binary(ByteOrder.LITTLE_ENDIAN,
"01012f0000000000000000000000000000333537343534303731363036313936ddf189075add9a32d97b54073025963e65849a3a59940d05fd8db655fc84bc6d"));
verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN,
diff --git a/test/org/traccar/protocol/CellocatorProtocolDecoderTest.java b/test/org/traccar/protocol/CellocatorProtocolDecoderTest.java
index fe03bc3d5..cdda0fca7 100644
--- a/test/org/traccar/protocol/CellocatorProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/CellocatorProtocolDecoderTest.java
@@ -13,6 +13,12 @@ public class CellocatorProtocolDecoderTest extends ProtocolTest {
CellocatorProtocolDecoder decoder = new CellocatorProtocolDecoder(new CellocatorProtocol());
verifyPosition(decoder, binary(ByteOrder.LITTLE_ENDIAN,
+ "4D434750008AD01500080103011804000000460020000000005E750000000000000000000000C34300040204DA4DA30367195703E803000000000000000001030F0802E10778"));
+
+ verifyPosition(decoder, binary(ByteOrder.LITTLE_ENDIAN,
+ "4D434750008AD01500080102011804000000360060000000005E750000000000000000000000C24300040204DA4DA30367195703E80300000000000000003B020F0802E107DF"));
+
+ verifyPosition(decoder, binary(ByteOrder.LITTLE_ENDIAN,
"4D4347500006000000081A02021204000000210062300000006B00E100000000000000000000E5A100040206614EA303181A57034E1200000000000000001525071403D60749"));
verifyPosition(decoder, binary(ByteOrder.LITTLE_ENDIAN,
diff --git a/test/org/traccar/protocol/CellocatorProtocolEncoderTest.java b/test/org/traccar/protocol/CellocatorProtocolEncoderTest.java
new file mode 100644
index 000000000..89850fb5f
--- /dev/null
+++ b/test/org/traccar/protocol/CellocatorProtocolEncoderTest.java
@@ -0,0 +1,26 @@
+package org.traccar.protocol;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+import org.traccar.model.Command;
+
+public class CellocatorProtocolEncoderTest extends ProtocolTest {
+
+ @Ignore
+ @Test
+ public void testEncode() throws Exception {
+
+ CellocatorProtocolEncoder encoder = new CellocatorProtocolEncoder();
+
+ Command command = new Command();
+ command.setDeviceId(1);
+ command.setType(Command.TYPE_OUTPUT_CONTROL);
+ command.set(Command.KEY_INDEX, 0);
+ command.set(Command.KEY_DATA, "1");
+
+ verifyCommand(encoder, command, binary("4D434750000000000000000000000303101000000000000026"));
+
+ }
+
+}
diff --git a/test/org/traccar/protocol/GalileoFrameDecoderTest.java b/test/org/traccar/protocol/GalileoFrameDecoderTest.java
new file mode 100644
index 000000000..1decd73d3
--- /dev/null
+++ b/test/org/traccar/protocol/GalileoFrameDecoderTest.java
@@ -0,0 +1,26 @@
+package org.traccar.protocol;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+import java.nio.ByteOrder;
+
+public class GalileoFrameDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ GalileoFrameDecoder decoder = new GalileoFrameDecoder();
+
+ Assert.assertEquals(
+ binary(ByteOrder.LITTLE_ENDIAN, "011780011102e603383633353931303238393630323437043200801c"),
+ decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "011780011102e603383633353931303238393630323437043200801c")));
+
+ Assert.assertEquals(
+ binary(ByteOrder.LITTLE_ENDIAN, "01d48304320010020520a5829f58300f50dc8a024c0965013300000000344102350740003a41e14b426610431b4459fa672a4500004601a050364c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e293000000043200100105202d829f58300f50dc8a024c0965013300000000344102350740003a41d04b426110431b445702882a4500004601a050374c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29400000004320010000520b5819f58300f50dc8a024c0965013300000000344102350740003a419e4b426a10431c4456fab72a4500004601a050434c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29500000004320010ff04203d819f58300f50dc8a024c0965013300000000344102350740003a41874b426310431c4454fe572a4500004601a050334c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29600000004320010fe0420c5809f58300f50dc8a024c0965013300000000344102350840003a41a24b426710431c4457fea72a4500004601a050214c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29700000004320010fd04204d809f58300f50dc8a024c0965013300000000344102350840003a41a34b426310431c4455f6772a4500004601a0502e4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29900000004320010fc0420d57f9f58300f50dc8a024c0965013300000000344102350840003a41bd4b426510431d4458fe672a4500004601a0501f4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29700000004320010fb04205d7f9f58300f50dc8a024c0965013300000000344102350840003a41b54b426310431d4456fa772a4500004601a0502d4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29500000004320010fa0420e57e9f58300f50dc8a024c0965013300000000344102350840003a41b24b426210431e4454fa872a4500004601a050fe4b510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29000000004320010f904206d7e9f58300f50dc8a024c0965013300000000344102350a40003a41af4b426710431f4458fea72a4500004601a0500a4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e28900000067c5"),
+ decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "01d48304320010020520a5829f58300f50dc8a024c0965013300000000344102350740003a41e14b426610431b4459fa672a4500004601a050364c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e293000000043200100105202d829f58300f50dc8a024c0965013300000000344102350740003a41d04b426110431b445702882a4500004601a050374c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29400000004320010000520b5819f58300f50dc8a024c0965013300000000344102350740003a419e4b426a10431c4456fab72a4500004601a050434c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29500000004320010ff04203d819f58300f50dc8a024c0965013300000000344102350740003a41874b426310431c4454fe572a4500004601a050334c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29600000004320010fe0420c5809f58300f50dc8a024c0965013300000000344102350840003a41a24b426710431c4457fea72a4500004601a050214c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29700000004320010fd04204d809f58300f50dc8a024c0965013300000000344102350840003a41a34b426310431c4455f6772a4500004601a0502e4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29900000004320010fc0420d57f9f58300f50dc8a024c0965013300000000344102350840003a41bd4b426510431d4458fe672a4500004601a0501f4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29700000004320010fb04205d7f9f58300f50dc8a024c0965013300000000344102350840003a41b54b426310431d4456fa772a4500004601a0502d4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29500000004320010fa0420e57e9f58300f50dc8a024c0965013300000000344102350840003a41b24b426210431e4454fa872a4500004601a050fe4b510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29000000004320010f904206d7e9f58300f50dc8a024c0965013300000000344102350a40003a41af4b426710431f4458fea72a4500004601a0500a4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e28900000067c5")));
+
+ }
+
+}
diff --git a/test/org/traccar/protocol/GalileoProtocolDecoderTest.java b/test/org/traccar/protocol/GalileoProtocolDecoderTest.java
index c18a652f7..28d40829a 100644
--- a/test/org/traccar/protocol/GalileoProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/GalileoProtocolDecoderTest.java
@@ -24,6 +24,9 @@ public class GalileoProtocolDecoderTest extends ProtocolTest {
verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN,
"011e8304320010270220dbd2f051300a90cf740328ac59033300000000347600351240012a41e92e42500f431f440006c814450f00460020500000510000520000530000540000550000560000570000580000600000610000620000a000a100a200a300a400a500a600a700a800a900aa00ab00ac00ad00ae00af00b00000b10000b20000b30000b40000b50000b60000b70000b80000b90000c000000000c100000000c200000000c300000000c400c500c600c700c800c900ca00cb00cc00cd00ce00cf00d000d100d200d471020000d60000d70000d80000d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f30000000004320010260220bdd2f051300590cf740328ac59033300000000347600351440090a41f02e427b0f431f44ff0db814450f00460000500000510000520000530000540000550000560000570000580000600000610000620000a000a100a200a300a400a500a600a700a800a900aa00ab00ac00ad00ae00af00b00000b10000b20000b30000b40000b50000b60000b70000b80000b90000c000000000c100000000c200000000c300000000c400c500c600c700c800c900ca00cb00cc00cd00ce00cf00d000d100d200d471020000d60000d70000d80000d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000043200102502208ed2f051300ed8d0740304ac5903330000000034a500350a40012a41ec2e422d0f431f440016b814450f00460020500000510000520000530000540000550000560000570000580000600000610000620000a000a100a200a300a400a500a600a700a800a900aa00ab00ac00ad00ae00af00b00000b10000b20000b30000b40000b50000b60000b70000b80000b90000c000000000c100000000c200000000c300000000c400c500c600c700c800c900ca00cb00cc00cd00ce00cf00d000d100d200d44d020000d60000d70000d80000d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000622e"));
+ verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN,
+ "01d48304320010020520a5829f58300f50dc8a024c0965013300000000344102350740003a41e14b426610431b4459fa672a4500004601a050364c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e293000000043200100105202d829f58300f50dc8a024c0965013300000000344102350740003a41d04b426110431b445702882a4500004601a050374c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29400000004320010000520b5819f58300f50dc8a024c0965013300000000344102350740003a419e4b426a10431c4456fab72a4500004601a050434c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29500000004320010ff04203d819f58300f50dc8a024c0965013300000000344102350740003a41874b426310431c4454fe572a4500004601a050334c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29600000004320010fe0420c5809f58300f50dc8a024c0965013300000000344102350840003a41a24b426710431c4457fea72a4500004601a050214c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29700000004320010fd04204d809f58300f50dc8a024c0965013300000000344102350840003a41a34b426310431c4455f6772a4500004601a0502e4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29900000004320010fc0420d57f9f58300f50dc8a024c0965013300000000344102350840003a41bd4b426510431d4458fe672a4500004601a0501f4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29700000004320010fb04205d7f9f58300f50dc8a024c0965013300000000344102350840003a41b54b426310431d4456fa772a4500004601a0502d4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29500000004320010fa0420e57e9f58300f50dc8a024c0965013300000000344102350840003a41b24b426210431e4454fa872a4500004601a050fe4b510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29000000004320010f904206d7e9f58300f50dc8a024c0965013300000000344102350a40003a41af4b426710431f4458fea72a4500004601a0500a4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e28900000067c5"));
+
}
}
diff --git a/test/org/traccar/protocol/Gl200ProtocolDecoderTest.java b/test/org/traccar/protocol/Gl200ProtocolDecoderTest.java
index a4b8985f1..e2ac176f0 100644
--- a/test/org/traccar/protocol/Gl200ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/Gl200ProtocolDecoderTest.java
@@ -10,6 +10,15 @@ public class Gl200ProtocolDecoderTest extends ProtocolTest {
Gl200ProtocolDecoder decoder = new Gl200ProtocolDecoder(new Gl200Protocol());
+ verifyNothing(decoder, text(
+ "+RESP:GTGSM,400201,862365030034940,STR,0234,0030,0870,2469,19,,0234,0030,0870,35ee,18,,0234,0030,0870,16ac,12,,0234,0030,0870,16b2,11,,0234,0030,0870,360f,6,,0234,0030,0870,165d,6,,0234,0030,0870,35ef,17,,20170215220049,008D$"));
+
+ verifyPosition(decoder, text(
+ "+RESP:GTSTR,400201,862365030034940,GL500,0,0,2,21.1,86,0,1.6,0,5.8,0.622831,51.582688,20170215090422,0234,0030,0870,35EF,,,,20170215220049,008C$"));
+
+ verifyPositions(decoder, text(
+ "+RESP:GTFRI,2C0402,867162020000816,,0,0,1,2,0.3,337,245.7,-82.373387,34.634011,20170215003054,,,,,,63,20170215003241,3EAB$"));
+
verifyNotNull(decoder, text(
"+RESP:GTWIF,210102,354524044608058,,4,c413e200ff14,-39,,,,c413e2010e55,-39,,,,c8d3ff04a837,-43,,,,42490f997c6d,-57,,,,,,,,100,20170201020055,0001$"));
diff --git a/test/org/traccar/protocol/H02FrameDecoderTest.java b/test/org/traccar/protocol/H02FrameDecoderTest.java
index 1505e25ac..3ced35d53 100644
--- a/test/org/traccar/protocol/H02FrameDecoderTest.java
+++ b/test/org/traccar/protocol/H02FrameDecoderTest.java
@@ -12,6 +12,10 @@ public class H02FrameDecoderTest extends ProtocolTest {
H02FrameDecoder decoder = new H02FrameDecoder(0);
Assert.assertEquals(
+ binary("2a48512c3335353438383032303131333931312c56312c3031323934352c412c353233312e37393238332c4e2c30313332342e31303731382c452c302e30352c302c3137303231372c464646464646464623"),
+ decoder.decode(null, null, binary("2a48512c3335353438383032303131333931312c56312c3031323934352c412c353233312e37393238332c4e2c30313332342e31303731382c452c302e30352c302c3137303231372c4646464646464646230d0a")));
+
+ Assert.assertEquals(
binary("2441060116601245431311165035313006004318210e000000fffffbffff0024"),
decoder.decode(null, null, binary("2441060116601245431311165035313006004318210e000000fffffbffff0024")));
diff --git a/test/org/traccar/protocol/H02ProtocolDecoderTest.java b/test/org/traccar/protocol/H02ProtocolDecoderTest.java
index 55bad63c8..90a1470c6 100644
--- a/test/org/traccar/protocol/H02ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/H02ProtocolDecoderTest.java
@@ -10,6 +10,12 @@ public class H02ProtocolDecoderTest extends ProtocolTest {
H02ProtocolDecoder decoder = new H02ProtocolDecoder(new H02Protocol());
+ verifyPosition(decoder, buffer(
+ "*HQ,4109179024,V19,103732,V,3853.2770,S,06205.8678,W,000.00,000,100217,,5492932630888,8954314165044716555?,FFFFFBFF#"));
+
+ verifyAttributes(decoder, buffer(
+ "*HQ,4109179024,NBR,103732,722,310,0,6,8106,32010,23,8101,22007,25,8106,12010,23,8106,22105,22,8101,22012,16,8106,42010,5,100217,FFFFFBFF,5#"));
+
verifyNothing(decoder, buffer(
"*HQ,355488020930796,V3,002339,62160,06,024852,035421,148,0,024852,035425,143,,022251,036482,137,,024852,000335,133,,024852,031751,133,,024852,035423,133,,02A1,0,X,010104,EFE7FBFF#"));
diff --git a/test/org/traccar/protocol/TaipProtocolDecoderTest.java b/test/org/traccar/protocol/TaipProtocolDecoderTest.java
index 871ec84b3..74956f51c 100644
--- a/test/org/traccar/protocol/TaipProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/TaipProtocolDecoderTest.java
@@ -11,6 +11,12 @@ public class TaipProtocolDecoderTest extends ProtocolTest {
TaipProtocolDecoder decoder = new TaipProtocolDecoder(new TaipProtocol(), false);
verifyPosition(decoder, text(
+ ">RCQ09000000000000-3460365-058381460000007F0000000000000115000FFFF1099;#0000;ID=555224;*05<"));
+
+ verifyPosition(decoder, text(
+ ">RBR00130217040848-3462200-05846708000175FF0022900003B3C13010800001118410+24061A;ID=555224;*07<"));
+
+ verifyPosition(decoder, text(
">REV451891352379+0307152+1016143700000012;SV=8;BL=4416;VO=8055;ID=356612026322000<"));
verifyPosition(decoder, text(
diff --git a/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java b/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java
index 22c9c4b4b..289a4f28d 100644
--- a/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java
@@ -14,6 +14,9 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest {
"000F313233343536373839303132333435"));
verifyPositions(decoder, false, binary(
+ "0000000000000000080100000113fc208dff00209cca800f14f650006f00d60400040004030101150316030001460000015d000100000000")); // invalid length and checksum
+
+ verifyPositions(decoder, false, binary(
"000000000000009f080400000159738f76b8012e13b796110ab27600d700000b00004e01000000014e000000000000000000000159738f6ee8012e13b796110ab27600d700000a00004e01000000014e01000b00791c179300000159738f6b00012e13b796110ab27600d700000a00004e01000000014e000000000000000000000159738f5f48012e13b796110ab27600d700000b00004e01000000014e01000b00791c17930400009671"));
verifyPositions(decoder, false, binary(
diff --git a/test/org/traccar/protocol/TmgProtocolDecoderTest.java b/test/org/traccar/protocol/TmgProtocolDecoderTest.java
index fb2576f95..cbfe82abc 100644
--- a/test/org/traccar/protocol/TmgProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/TmgProtocolDecoderTest.java
@@ -11,6 +11,21 @@ public class TmgProtocolDecoderTest extends ProtocolTest {
TmgProtocolDecoder decoder = new TmgProtocolDecoder(new TmgProtocol());
verifyPosition(decoder, text(
+ "$ion,H,868324023777431,27012017,101057,4,2830.2952,N,07705.2532,E,0.0,202.38,225.9,1.22,8,20,N.A,0,N.A,1,4.09,00.0,00000111,00000000,1101,00.0-00.0,00.0-0.0,4.42,01.02,#"));
+
+ verifyPosition(decoder, text(
+ "$iof,H,868324023777431,27012017,101111,4,2830.2952,N,07705.2532,E,0.0,202.38,225.9,0.87,11,21,N.A,25,N.A,0,4.09,00.0,00000111,00000000,1110,00.0-00.0,00.0-0.0,4.42,01.02,#"));
+
+ verifyPosition(decoder, text(
+ "$rmv,L,868324023777431,27012017,101141,4,2830.2952,N,07705.2532,E,0.0,202.38,225.9,0.86,12,21,VODAFONE - DELH,24,3220,0,4.11,00.0,00000111,00000000,1110,00.0-00.0,00.0-0.0,4.42,01.02,#"));
+
+ verifyPosition(decoder, text(
+ "$rnc,H,868324023777431,27012017,101013,4,2830.2923,N,07705.2551,E,0.0,9.65,226.0,0.88,12,21,VODAFONE - DELH,28,3220,0,4.14,07.4,00000111,00000000,1111,00.0-00.0,00.0-0.0,4.42,01.02,#"));
+
+ verifyPosition(decoder, text(
+ "$ebl,H,868324023777431,27012017,101046,4,2830.2923,N,07705.2551,E,0.0,9.65,226.0,0.97,11,21,VODAFONE - DELH,25,3220,0,4.11,00.0,00000111,00000000,1110,00.0-00.0,00.0-0.0,4.42,01.02,#"));
+
+ verifyPosition(decoder, text(
"$nor,L,868324023777431,17012017,001023,4,2830.2977,N,07705.2478,E,0.0,207.07,229.2,0.97,11,22,IDEA CELLULAR L,18,DCDE,0,4.09,12.9,00000111,00000000,1111,00.0-00.0,00.0-0.0,3.59,01.02,#"));
verifyPosition(decoder, text(
diff --git a/tools/swagger2html.py b/tools/swagger2html.py
index a3488835c..1121f04c9 100755
--- a/tools/swagger2html.py
+++ b/tools/swagger2html.py
@@ -224,11 +224,17 @@ def make_responses_table(responses):
except KeyError as e:
handleException('KeyError', e)
+def sorted_by_method(section):
+ sorting_function = lambda x: [ 'GET', 'POST', 'PUT', 'DELETE' ].index(
+ x['title'].split(' ')[0]
+ )
+ return sorted(sorted(section), key=sorting_function)
+
def make_paths(sections, json_data):
md = '<h2><a name="paths"></a>Paths</h2>\n'
for key in sorted(sections):
md += '<h3><a name="paths_{0}"></a>{0}</h3>\n'.format(key)
- for section in sections[key]:
+ for section in sorted_by_method(sections[key]):
md += '<h4><a name="{}"></a><code>{}</code></h4>\n'.format(
section['href'], section['title']
)
@@ -256,7 +262,7 @@ def make_contents(path_section, json_data):
for key in sorted(path_section):
md += ' <li><a href="#paths_{0}">{0}</a>\n'.format(key)
md += ' <ul>\n'
- for section in path_section[key]:
+ for section in sorted_by_method(path_section[key]):
md += ' <li><a href="#{}">{}</a></li>\n'.format(
section['href'], section['title']
)