aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/org/traccar/BaseProtocol.java4
-rw-r--r--src/org/traccar/ExtendedObjectDecoder.java4
-rw-r--r--src/org/traccar/api/MediaFilter.java2
-rw-r--r--src/org/traccar/api/SecurityRequestFilter.java4
-rw-r--r--src/org/traccar/api/resource/SessionResource.java6
-rw-r--r--src/org/traccar/events/AlertEventHandler.java24
-rw-r--r--src/org/traccar/helper/DataConverter.java47
-rw-r--r--src/org/traccar/helper/Hashing.java9
-rw-r--r--src/org/traccar/helper/ObdDecoder.java31
-rw-r--r--src/org/traccar/model/Position.java1
-rw-r--r--src/org/traccar/protocol/At2000ProtocolDecoder.java4
-rw-r--r--src/org/traccar/protocol/AtrackProtocolDecoder.java17
-rw-r--r--src/org/traccar/protocol/CastelProtocol.java8
-rw-r--r--src/org/traccar/protocol/CastelProtocolDecoder.java1
-rw-r--r--src/org/traccar/protocol/CastelProtocolEncoder.java73
-rw-r--r--src/org/traccar/protocol/CautelaProtocol.java47
-rw-r--r--src/org/traccar/protocol/CautelaProtocolDecoder.java77
-rw-r--r--src/org/traccar/protocol/ContinentalProtocol.java43
-rw-r--r--src/org/traccar/protocol/ContinentalProtocolDecoder.java93
-rw-r--r--src/org/traccar/protocol/DmtProtocolDecoder.java263
-rw-r--r--src/org/traccar/protocol/EelinkProtocolEncoder.java4
-rw-r--r--src/org/traccar/protocol/FlespiProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/Gl200TextProtocolDecoder.java100
-rw-r--r--src/org/traccar/protocol/HuabaoProtocolEncoder.java6
-rw-r--r--src/org/traccar/protocol/MeiligaoProtocolEncoder.java4
-rw-r--r--src/org/traccar/protocol/RuptelaProtocolDecoder.java6
-rw-r--r--src/org/traccar/protocol/SigfoxProtocolDecoder.java4
-rw-r--r--src/org/traccar/protocol/T55ProtocolDecoder.java8
-rw-r--r--src/org/traccar/protocol/T800xProtocolEncoder.java4
-rw-r--r--src/org/traccar/protocol/TaipProtocolDecoder.java72
-rw-r--r--src/org/traccar/protocol/TeltonikaProtocolDecoder.java7
-rw-r--r--src/org/traccar/protocol/WatchProtocolDecoder.java89
-rw-r--r--src/org/traccar/protocol/WatchProtocolEncoder.java4
-rw-r--r--src/org/traccar/protocol/XirgoProtocolDecoder.java69
-rw-r--r--src/org/traccar/protocol/Xt2400ProtocolDecoder.java4
35 files changed, 875 insertions, 266 deletions
diff --git a/src/org/traccar/BaseProtocol.java b/src/org/traccar/BaseProtocol.java
index 90b9f21f2..07adbea5e 100644
--- a/src/org/traccar/BaseProtocol.java
+++ b/src/org/traccar/BaseProtocol.java
@@ -18,9 +18,9 @@ package org.traccar;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.traccar.database.ActiveDevice;
+import org.traccar.helper.DataConverter;
import org.traccar.model.Command;
-import javax.xml.bind.DatatypeConverter;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
@@ -79,7 +79,7 @@ public abstract class BaseProtocol implements Protocol {
if (activeDevice.getChannel().getPipeline().get(StringEncoder.class) != null) {
activeDevice.write(data);
} else {
- activeDevice.write(ChannelBuffers.wrappedBuffer(DatatypeConverter.parseHexBinary(data)));
+ activeDevice.write(ChannelBuffers.wrappedBuffer(DataConverter.parseHex(data)));
}
} else {
throw new RuntimeException("Command " + command.getType() + " is not supported in protocol " + getName());
diff --git a/src/org/traccar/ExtendedObjectDecoder.java b/src/org/traccar/ExtendedObjectDecoder.java
index 268e6f688..75a24212f 100644
--- a/src/org/traccar/ExtendedObjectDecoder.java
+++ b/src/org/traccar/ExtendedObjectDecoder.java
@@ -23,9 +23,9 @@ import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelUpstreamHandler;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.MessageEvent;
+import org.traccar.helper.DataConverter;
import org.traccar.model.Position;
-import javax.xml.bind.DatatypeConverter;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
@@ -39,7 +39,7 @@ public abstract class ExtendedObjectDecoder implements ChannelUpstreamHandler {
ChannelBuffer buf = (ChannelBuffer) originalMessage;
position.set(Position.KEY_ORIGINAL, ChannelBuffers.hexDump(buf, 0, buf.writerIndex()));
} else if (originalMessage instanceof String) {
- position.set(Position.KEY_ORIGINAL, DatatypeConverter.printHexBinary(
+ position.set(Position.KEY_ORIGINAL, DataConverter.printHex(
((String) originalMessage).getBytes(StandardCharsets.US_ASCII)));
}
}
diff --git a/src/org/traccar/api/MediaFilter.java b/src/org/traccar/api/MediaFilter.java
index 4685ce05b..25e242b01 100644
--- a/src/org/traccar/api/MediaFilter.java
+++ b/src/org/traccar/api/MediaFilter.java
@@ -43,7 +43,7 @@ public class MediaFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
- HttpServletResponse httpResponse = ((HttpServletResponse) response);
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
try {
HttpSession session = ((HttpServletRequest) request).getSession(false);
Long userId = null;
diff --git a/src/org/traccar/api/SecurityRequestFilter.java b/src/org/traccar/api/SecurityRequestFilter.java
index 7024bdbc9..aace9f705 100644
--- a/src/org/traccar/api/SecurityRequestFilter.java
+++ b/src/org/traccar/api/SecurityRequestFilter.java
@@ -17,6 +17,7 @@ package org.traccar.api;
import org.traccar.Context;
import org.traccar.api.resource.SessionResource;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.Log;
import org.traccar.model.User;
@@ -28,7 +29,6 @@ import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
-import javax.xml.bind.DatatypeConverter;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
@@ -43,7 +43,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter {
public static String[] decodeBasicAuth(String auth) {
auth = auth.replaceFirst("[B|b]asic ", "");
- byte[] decodedBytes = DatatypeConverter.parseBase64Binary(auth);
+ byte[] decodedBytes = DataConverter.parseBase64(auth);
if (decodedBytes != null && decodedBytes.length > 0) {
return new String(decodedBytes, StandardCharsets.US_ASCII).split(":", 2);
}
diff --git a/src/org/traccar/api/resource/SessionResource.java b/src/org/traccar/api/resource/SessionResource.java
index 2a0bd4364..fd331c766 100644
--- a/src/org/traccar/api/resource/SessionResource.java
+++ b/src/org/traccar/api/resource/SessionResource.java
@@ -17,6 +17,7 @@ package org.traccar.api.resource;
import org.traccar.Context;
import org.traccar.api.BaseResource;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.LogAction;
import org.traccar.model.User;
@@ -34,7 +35,6 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
@@ -63,11 +63,11 @@ public class SessionResource extends BaseResource {
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(USER_COOKIE_KEY)) {
- byte[] emailBytes = DatatypeConverter.parseBase64Binary(
+ byte[] emailBytes = DataConverter.parseBase64(
URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII.name()));
email = new String(emailBytes, StandardCharsets.UTF_8);
} else if (cookie.getName().equals(PASS_COOKIE_KEY)) {
- byte[] passwordBytes = DatatypeConverter.parseBase64Binary(
+ byte[] passwordBytes = DataConverter.parseBase64(
URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII.name()));
password = new String(passwordBytes, StandardCharsets.UTF_8);
}
diff --git a/src/org/traccar/events/AlertEventHandler.java b/src/org/traccar/events/AlertEventHandler.java
index 003ccb662..7db371c70 100644
--- a/src/org/traccar/events/AlertEventHandler.java
+++ b/src/org/traccar/events/AlertEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 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,18 +19,34 @@ import java.util.Collections;
import java.util.Map;
import org.traccar.BaseEventHandler;
+import org.traccar.Context;
import org.traccar.model.Event;
import org.traccar.model.Position;
public class AlertEventHandler extends BaseEventHandler {
+ private final boolean ignoreDuplicateAlerts;
+
+ public AlertEventHandler() {
+ ignoreDuplicateAlerts = Context.getConfig().getBoolean("event.ignoreDuplicateAlerts");
+ }
+
@Override
protected Map<Event, Position> analyzePosition(Position position) {
Object alarm = position.getAttributes().get(Position.KEY_ALARM);
if (alarm != null) {
- Event event = new Event(Event.TYPE_ALARM, position.getDeviceId(), position.getId());
- event.set(Position.KEY_ALARM, (String) alarm);
- return Collections.singletonMap(event, position);
+ boolean ignoreAlert = false;
+ if (ignoreDuplicateAlerts) {
+ Position lastPosition = Context.getIdentityManager().getLastPosition(position.getDeviceId());
+ if (lastPosition != null && alarm.equals(lastPosition.getAttributes().get(Position.KEY_ALARM))) {
+ ignoreAlert = true;
+ }
+ }
+ if (!ignoreAlert) {
+ Event event = new Event(Event.TYPE_ALARM, position.getDeviceId(), position.getId());
+ event.set(Position.KEY_ALARM, (String) alarm);
+ return Collections.singletonMap(event, position);
+ }
}
return null;
}
diff --git a/src/org/traccar/helper/DataConverter.java b/src/org/traccar/helper/DataConverter.java
new file mode 100644
index 000000000..7abd4ae93
--- /dev/null
+++ b/src/org/traccar/helper/DataConverter.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 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 org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+
+public final class DataConverter {
+
+ private DataConverter() {
+ }
+
+ public static byte[] parseHex(String string) {
+ try {
+ return Hex.decodeHex(string);
+ } catch (DecoderException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static String printHex(byte[] data) {
+ return Hex.encodeHexString(data);
+ }
+
+ public static byte[] parseBase64(String string) {
+ return Base64.decodeBase64(string);
+ }
+
+ public static String printBase64(byte[] data) {
+ return Base64.encodeBase64String(data);
+ }
+
+}
diff --git a/src/org/traccar/helper/Hashing.java b/src/org/traccar/helper/Hashing.java
index 3fcc124fa..e91310eda 100644
--- a/src/org/traccar/helper/Hashing.java
+++ b/src/org/traccar/helper/Hashing.java
@@ -17,7 +17,6 @@ package org.traccar.helper;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
-import javax.xml.bind.DatatypeConverter;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
@@ -75,13 +74,13 @@ public final class Hashing {
RANDOM.nextBytes(salt);
byte[] hash = function(password.toCharArray(), salt);
return new HashingResult(
- DatatypeConverter.printHexBinary(hash),
- DatatypeConverter.printHexBinary(salt));
+ DataConverter.printHex(hash),
+ DataConverter.printHex(salt));
}
public static boolean validatePassword(String password, String hashHex, String saltHex) {
- byte[] hash = DatatypeConverter.parseHexBinary(hashHex);
- byte[] salt = DatatypeConverter.parseHexBinary(saltHex);
+ byte[] hash = DataConverter.parseHex(hashHex);
+ byte[] salt = DataConverter.parseHex(saltHex);
return slowEquals(hash, function(password.toCharArray(), salt));
}
diff --git a/src/org/traccar/helper/ObdDecoder.java b/src/org/traccar/helper/ObdDecoder.java
index 4bc3bcdfb..1bdcce352 100644
--- a/src/org/traccar/helper/ObdDecoder.java
+++ b/src/org/traccar/helper/ObdDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2018 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.
@@ -29,15 +29,6 @@ public final class ObdDecoder {
private static final int MODE_FREEZE_FRAME = 0x02;
private static final int MODE_CODES = 0x03;
- private static final int PID_ENGINE_LOAD = 0x04;
- private static final int PID_COOLANT_TEMPERATURE = 0x05;
- private static final int PID_ENGINE_RPM = 0x0C;
- private static final int PID_VEHICLE_SPEED = 0x0D;
- private static final int PID_THROTTLE_POSITION = 0x11;
- private static final int PID_MIL_DISTANCE = 0x21;
- private static final int PID_FUEL_LEVEL = 0x2F;
- private static final int PID_DISTANCE_CLEARED = 0x31;
-
public static Map.Entry<String, Object> decode(int mode, String value) {
switch (mode) {
case MODE_CURRENT:
@@ -86,21 +77,25 @@ public final class ObdDecoder {
public static Map.Entry<String, Object> decodeData(int pid, int value, boolean convert) {
switch (pid) {
- case PID_ENGINE_LOAD:
+ case 0x04:
return createEntry(Position.KEY_ENGINE_LOAD, convert ? value * 100 / 255 : value);
- case PID_COOLANT_TEMPERATURE:
+ case 0x05:
return createEntry(Position.KEY_COOLANT_TEMP, convert ? value - 40 : value);
- case PID_ENGINE_RPM:
+ case 0x0B:
+ return createEntry("mapIntake", value);
+ case 0x0C:
return createEntry(Position.KEY_RPM, convert ? value / 4 : value);
- case PID_VEHICLE_SPEED:
+ case 0x0D:
return createEntry(Position.KEY_OBD_SPEED, value);
- case PID_THROTTLE_POSITION:
+ case 0x0F:
+ return createEntry("intakeTemp", convert ? value - 40 : value);
+ case 0x11:
return createEntry(Position.KEY_THROTTLE, convert ? value * 100 / 255 : value);
- case PID_MIL_DISTANCE:
+ case 0x21:
return createEntry("milDistance", value);
- case PID_FUEL_LEVEL:
+ case 0x2F:
return createEntry(Position.KEY_FUEL_LEVEL, convert ? value * 100 / 255 : value);
- case PID_DISTANCE_CLEARED:
+ case 0x31:
return createEntry("clearedDistance", value);
default:
return null;
diff --git a/src/org/traccar/model/Position.java b/src/org/traccar/model/Position.java
index fdecb7e20..0e8bd9a6e 100644
--- a/src/org/traccar/model/Position.java
+++ b/src/org/traccar/model/Position.java
@@ -121,6 +121,7 @@ public class Position extends Message {
public static final String ALARM_GPS_ANTENNA_CUT = "gpsAntennaCut";
public static final String ALARM_ACCIDENT = "accident";
public static final String ALARM_TOW = "tow";
+ public static final String ALARM_IDLE = "idle";
public static final String ALARM_ACCELERATION = "hardAcceleration";
public static final String ALARM_BRAKING = "hardBraking";
public static final String ALARM_CORNERING = "hardCornering";
diff --git a/src/org/traccar/protocol/At2000ProtocolDecoder.java b/src/org/traccar/protocol/At2000ProtocolDecoder.java
index 06d80c497..e0f2b4278 100644
--- a/src/org/traccar/protocol/At2000ProtocolDecoder.java
+++ b/src/org/traccar/protocol/At2000ProtocolDecoder.java
@@ -20,13 +20,13 @@ import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
-import javax.xml.bind.DatatypeConverter;
import java.net.SocketAddress;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
@@ -84,7 +84,7 @@ public class At2000ProtocolDecoder extends BaseProtocolDecoder {
IvParameterSpec ivSpec = new IvParameterSpec(iv);
SecretKeySpec keySpec = new SecretKeySpec(
- DatatypeConverter.parseHexBinary("000102030405060708090a0b0c0d0e0f"), "AES");
+ DataConverter.parseHex("000102030405060708090a0b0c0d0e0f"), "AES");
cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
diff --git a/src/org/traccar/protocol/AtrackProtocolDecoder.java b/src/org/traccar/protocol/AtrackProtocolDecoder.java
index 236b608d6..8138f0fcb 100644
--- a/src/org/traccar/protocol/AtrackProtocolDecoder.java
+++ b/src/org/traccar/protocol/AtrackProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2018 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,6 +36,7 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AtrackProtocolDecoder extends BaseProtocolDecoder {
@@ -43,6 +44,7 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
private static final int MIN_DATA_LENGTH = 40;
private boolean longDate;
+ private boolean decimalFuel;
private boolean custom;
private String form;
@@ -52,6 +54,7 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
longDate = Context.getConfig().getBoolean(getProtocolName() + ".longDate");
+ decimalFuel = Context.getConfig().getBoolean(getProtocolName() + ".decimalFuel");
custom = Context.getConfig().getBoolean(getProtocolName() + ".custom");
form = Context.getConfig().getString(getProtocolName() + ".form");
@@ -330,7 +333,17 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.PREFIX_TEMP + 1, buf.readShort() * 0.1);
position.set(Position.PREFIX_TEMP + 2, buf.readShort() * 0.1);
- position.set("message", readString(buf));
+ String message = readString(buf);
+ if (message != null && !message.isEmpty()) {
+ Pattern pattern = Pattern.compile("FULS:F=(\\p{XDigit}+) t=(\\p{XDigit}+) N=(\\p{XDigit}+)");
+ Matcher matcher = pattern.matcher(message);
+ if (matcher.find()) {
+ int value = Integer.parseInt(matcher.group(3), decimalFuel ? 10 : 16);
+ position.set(Position.KEY_FUEL_LEVEL, value * 0.1);
+ } else {
+ position.set("message", message);
+ }
+ }
if (custom) {
String form = this.form;
diff --git a/src/org/traccar/protocol/CastelProtocol.java b/src/org/traccar/protocol/CastelProtocol.java
index db9df0674..d5ba5cd55 100644
--- a/src/org/traccar/protocol/CastelProtocol.java
+++ b/src/org/traccar/protocol/CastelProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2018 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,6 +21,7 @@ import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.TrackerServer;
+import org.traccar.model.Command;
import java.nio.ByteOrder;
import java.util.List;
@@ -29,6 +30,9 @@ public class CastelProtocol extends BaseProtocol {
public CastelProtocol() {
super("castel");
+ setSupportedDataCommands(
+ Command.TYPE_ENGINE_STOP,
+ Command.TYPE_ENGINE_RESUME);
}
@Override
@@ -37,6 +41,7 @@ public class CastelProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0));
+ pipeline.addLast("objectEncoder", new CastelProtocolEncoder());
pipeline.addLast("objectDecoder", new CastelProtocolDecoder(CastelProtocol.this));
}
};
@@ -46,6 +51,7 @@ public class CastelProtocol extends BaseProtocol {
server = new TrackerServer(new ConnectionlessBootstrap(), getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("objectEncoder", new CastelProtocolEncoder());
pipeline.addLast("objectDecoder", new CastelProtocolDecoder(CastelProtocol.this));
}
};
diff --git a/src/org/traccar/protocol/CastelProtocolDecoder.java b/src/org/traccar/protocol/CastelProtocolDecoder.java
index ebd3d202c..44a5e213c 100644
--- a/src/org/traccar/protocol/CastelProtocolDecoder.java
+++ b/src/org/traccar/protocol/CastelProtocolDecoder.java
@@ -96,6 +96,7 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder {
public static final short MSG_CC_LOGIN = 0x4001;
public static final short MSG_CC_LOGIN_RESPONSE = (short) 0x8001;
public static final short MSG_CC_HEARTBEAT = 0x4206;
+ public static final short MSG_CC_PETROL_CONTROL = 0x4583;
public static final short MSG_CC_HEARTBEAT_RESPONSE = (short) 0x8206;
private Position readPosition(DeviceSession deviceSession, ChannelBuffer buf) {
diff --git a/src/org/traccar/protocol/CastelProtocolEncoder.java b/src/org/traccar/protocol/CastelProtocolEncoder.java
new file mode 100644
index 000000000..7ba33ca6d
--- /dev/null
+++ b/src/org/traccar/protocol/CastelProtocolEncoder.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2018 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.Context;
+import org.traccar.helper.Checksum;
+import org.traccar.helper.Log;
+import org.traccar.model.Command;
+
+import java.nio.ByteOrder;
+import java.nio.charset.StandardCharsets;
+
+public class CastelProtocolEncoder extends BaseProtocolEncoder {
+
+ private ChannelBuffer encodeContent(long deviceId, short type, ChannelBuffer content) {
+ ChannelBuffer buf = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0);
+ String uniqueId = Context.getIdentityManager().getById(deviceId).getUniqueId();
+
+ buf.writeByte('@');
+ buf.writeByte('@');
+
+ buf.writeShort(2 + 2 + 1 + 20 + content.readableBytes()); // length
+
+ buf.writeByte(4); // protocol version
+
+ buf.writeBytes(uniqueId.getBytes(StandardCharsets.US_ASCII));
+ buf.writeZero(20 - uniqueId.length());
+
+ buf.writeShort(ChannelBuffers.swapShort(type));
+ buf.writeBytes(content);
+
+ buf.writeShort(Checksum.crc16(Checksum.CRC16_X25, buf.toByteBuffer()));
+
+ buf.writeByte('\r');
+ buf.writeByte('\n');
+
+ return buf;
+ }
+
+ @Override
+ protected Object encodeCommand(Command command) {
+ ChannelBuffer content = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0);
+ switch (command.getType()) {
+ case Command.TYPE_ENGINE_STOP:
+ content.writeByte(1);
+ return encodeContent(command.getDeviceId(), CastelProtocolDecoder.MSG_CC_PETROL_CONTROL, content);
+ case Command.TYPE_ENGINE_RESUME:
+ content.writeByte(0);
+ return encodeContent(command.getDeviceId(), CastelProtocolDecoder.MSG_CC_PETROL_CONTROL, content);
+ default:
+ Log.warning(new UnsupportedOperationException(command.getType()));
+ break;
+ }
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/protocol/CautelaProtocol.java b/src/org/traccar/protocol/CautelaProtocol.java
new file mode 100644
index 000000000..89ab7a1d0
--- /dev/null
+++ b/src/org/traccar/protocol/CautelaProtocol.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 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.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;
+
+public class CautelaProtocol extends BaseProtocol {
+
+ public CautelaProtocol() {
+ super("cautela");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ServerBootstrap(), getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024));
+ pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
+ pipeline.addLast("objectDecoder", new CautelaProtocolDecoder(CautelaProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/CautelaProtocolDecoder.java b/src/org/traccar/protocol/CautelaProtocolDecoder.java
new file mode 100644
index 000000000..d7bf4fb51
--- /dev/null
+++ b/src/org/traccar/protocol/CautelaProtocolDecoder.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018 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.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;
+
+public class CautelaProtocolDecoder extends BaseProtocolDecoder {
+
+ public CautelaProtocolDecoder(CautelaProtocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .number("(d+),") // type
+ .number("(d+),") // imei
+ .number("(dd),(dd),(dd),") // date (ddmmyy)
+ .number("(-?d+.d+),") // latitude
+ .number("(-?d+.d+),") // longitude
+ .number("(dd)(dd),") // time (hhmm)
+ .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;
+ }
+
+ String type = parser.next();
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ DateBuilder dateBuilder = new DateBuilder();
+ dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
+
+ position.setValid(true);
+ position.setLatitude(parser.nextDouble());
+ position.setLongitude(parser.nextDouble());
+
+ dateBuilder.setHour(parser.nextInt()).setMinute(parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+
+ return position;
+ }
+
+}
diff --git a/src/org/traccar/protocol/ContinentalProtocol.java b/src/org/traccar/protocol/ContinentalProtocol.java
new file mode 100644
index 000000000..e2b1226cf
--- /dev/null
+++ b/src/org/traccar/protocol/ContinentalProtocol.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 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.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder;
+import org.traccar.BaseProtocol;
+import org.traccar.TrackerServer;
+
+import java.util.List;
+
+public class ContinentalProtocol extends BaseProtocol {
+
+ public ContinentalProtocol() {
+ super("continental");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ serverList.add(new TrackerServer(new ServerBootstrap(), getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 2, 2));
+ pipeline.addLast("objectDecoder", new ContinentalProtocolDecoder(ContinentalProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/ContinentalProtocolDecoder.java b/src/org/traccar/protocol/ContinentalProtocolDecoder.java
new file mode 100644
index 000000000..2138eb39e
--- /dev/null
+++ b/src/org/traccar/protocol/ContinentalProtocolDecoder.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2018 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.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.Date;
+
+public class ContinentalProtocolDecoder extends BaseProtocolDecoder {
+
+ public ContinentalProtocolDecoder(ContinentalProtocol protocol) {
+ super(protocol);
+ }
+
+ public static final int MSG_KEEPALIVE = 0x00;
+ public static final int MSG_STATUS = 0x02;
+ public static final int MSG_ACK = 0x06;
+ public static final int MSG_NACK = 0x15;
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ChannelBuffer buf = (ChannelBuffer) msg;
+
+ buf.skipBytes(2); // header
+ buf.readUnsignedShort(); // length
+ buf.readUnsignedByte(); // software version
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(buf.readUnsignedInt()));
+ if (deviceSession == null) {
+ return null;
+ }
+
+ buf.readUnsignedByte(); // product
+
+ int type = buf.readUnsignedByte();
+
+ if (type == MSG_STATUS) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setFixTime(new Date(buf.readUnsignedInt() * 1000L));
+
+ buf.readUnsignedByte();
+ position.setLatitude(buf.readMedium() / 3600.0);
+
+ buf.readUnsignedByte();
+ position.setLongitude(buf.readMedium() / 3600.0);
+
+ position.setCourse(buf.readUnsignedShort());
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort()));
+
+ position.setValid(buf.readUnsignedByte() > 0);
+
+ position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000L));
+
+ position.set(Position.KEY_EVENT, buf.readUnsignedShort());
+ position.set(Position.KEY_INPUT, buf.readUnsignedShort());
+ position.set(Position.KEY_OUTPUT, buf.readUnsignedShort());
+ position.set(Position.KEY_BATTERY, buf.readUnsignedByte());
+ position.set(Position.KEY_DEVICE_TEMP, buf.readByte());
+
+ buf.readUnsignedShort(); // reserved
+
+ return position;
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/protocol/DmtProtocolDecoder.java b/src/org/traccar/protocol/DmtProtocolDecoder.java
index 74db5a6f7..30a6ae13a 100644
--- a/src/org/traccar/protocol/DmtProtocolDecoder.java
+++ b/src/org/traccar/protocol/DmtProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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,6 +21,7 @@ import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
import org.traccar.helper.BitUtil;
+import org.traccar.helper.DateBuilder;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
@@ -42,6 +43,7 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_DATA_RECORD = 0x04;
public static final int MSG_COMMIT = 0x05;
public static final int MSG_COMMIT_RESPONSE = 0x06;
+ public static final int MSG_DATA_RECORD_64 = 0x10;
public static final int MSG_CANNED_REQUEST_1 = 0x14;
public static final int MSG_CANNED_RESPONSE_1 = 0x15;
@@ -61,142 +63,221 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder {
}
}
- @Override
- protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+ private List<Position> decodeFixed64(Channel channel, SocketAddress remoteAddress, ChannelBuffer buf) {
- ChannelBuffer buf = (ChannelBuffer) msg;
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
+ if (deviceSession == null) {
+ return null;
+ }
- buf.skipBytes(2); // header
+ List<Position> positions = new LinkedList<>();
- int type = buf.readUnsignedByte();
+ while (buf.readableBytes() >= 64) {
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
- buf.readUnsignedShort(); // length
+ buf.readByte(); // type
- if (type == MSG_HELLO) {
+ position.set(Position.KEY_INDEX, buf.readUnsignedInt());
- buf.readUnsignedInt(); // device serial number
+ long time = buf.readUnsignedInt();
+ position.setTime(new DateBuilder()
+ .setYear((int) (2000 + (time & 0x3F)))
+ .setMonth((int) (time >> 6) & 0xF)
+ .setDay((int) (time >> 10) & 0x1F)
+ .setHour((int) (time >> 15) & 0x1F)
+ .setMinute((int) (time >> 20) & 0x3F)
+ .setSecond((int) (time >> 26) & 0x3F)
+ .getDate());
- DeviceSession deviceSession = getDeviceSession(
- channel, remoteAddress, buf.readBytes(15).toString(StandardCharsets.US_ASCII));
+ position.setLongitude(buf.readInt() * 0.0000001);
+ position.setLatitude(buf.readInt() * 0.0000001);
+ position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShort()));
+ position.setCourse(buf.readUnsignedByte() * 2);
+ position.setAltitude(buf.readShort());
- ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0);
- response.writeInt((int) ((System.currentTimeMillis() - 1356998400000L) / 1000));
- response.writeInt(deviceSession != null ? 0 : 1); // flags
- sendResponse(channel, MSG_HELLO_RESPONSE, response);
+ buf.readUnsignedShort(); // position accuracy
+ buf.readUnsignedByte(); // speed accuracy
- } else if (type == MSG_COMMIT) {
+ position.set(Position.KEY_EVENT, buf.readUnsignedByte());
- ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0);
- response.writeByte(1); // flags (success)
- sendResponse(channel, MSG_COMMIT_RESPONSE, response);
+ position.setValid(BitUtil.check(buf.readByte(), 0));
- } else if (type == MSG_CANNED_REQUEST_1) {
+ position.set(Position.KEY_INPUT, buf.readUnsignedInt());
+ position.set(Position.KEY_OUTPUT, buf.readUnsignedShort());
- ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0);
- response.writeBytes(new byte[12]);
- sendResponse(channel, MSG_CANNED_RESPONSE_1, response);
+ for (int i = 1; i <= 5; i++) {
+ position.set(Position.PREFIX_ADC + i, buf.readShort());
+ }
- } else if (type == MSG_CANNED_REQUEST_2) {
+ position.set(Position.KEY_DEVICE_TEMP, buf.readByte());
- sendResponse(channel, MSG_CANNED_RESPONSE_2, null);
+ buf.readShort(); // accelerometer x
+ buf.readShort(); // accelerometer y
+ buf.readShort(); // accelerometer z
- } else if (type == MSG_DATA_RECORD) {
+ buf.skipBytes(8); // device id
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
- if (deviceSession == null) {
- return null;
- }
+ position.set(Position.KEY_PDOP, buf.readUnsignedShort() * 0.01);
- List<Position> positions = new LinkedList<>();
+ buf.skipBytes(2); // reserved
- while (buf.readable()) {
+ buf.readUnsignedShort(); // checksum
- int recordEnd = buf.readerIndex() + buf.readUnsignedShort();
+ positions.add(position);
+ }
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
+ return positions;
+ }
- position.set(Position.KEY_INDEX, buf.readUnsignedInt());
+ private List<Position> decodeStandard(Channel channel, SocketAddress remoteAddress, ChannelBuffer buf) {
- position.setDeviceTime(new Date(1356998400000L + buf.readUnsignedInt() * 1000)); // since 1 Jan 2013
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
+ if (deviceSession == null) {
+ return null;
+ }
- position.set(Position.KEY_EVENT, buf.readUnsignedByte());
+ List<Position> positions = new LinkedList<>();
- while (buf.readerIndex() < recordEnd) {
+ while (buf.readable()) {
+ int recordEnd = buf.readerIndex() + buf.readUnsignedShort();
- int fieldId = buf.readUnsignedByte();
- int fieldLength = buf.readUnsignedByte();
- int fieldEnd = buf.readerIndex() + (fieldLength == 255 ? buf.readUnsignedShort() : fieldLength);
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
- if (fieldId == 0) {
+ position.set(Position.KEY_INDEX, buf.readUnsignedInt());
- position.setFixTime(new Date(1356998400000L + buf.readUnsignedInt() * 1000));
- position.setLatitude(buf.readInt() * 0.0000001);
- position.setLongitude(buf.readInt() * 0.0000001);
- position.setAltitude(buf.readShort());
- position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShort()));
+ position.setDeviceTime(new Date(1356998400000L + buf.readUnsignedInt() * 1000)); // since 1 Jan 2013
- buf.readUnsignedByte(); // speed accuracy
+ position.set(Position.KEY_EVENT, buf.readUnsignedByte());
- position.setCourse(buf.readUnsignedByte() * 2);
+ while (buf.readerIndex() < recordEnd) {
- position.set(Position.KEY_PDOP, buf.readUnsignedByte() * 0.1);
+ int fieldId = buf.readUnsignedByte();
+ int fieldLength = buf.readUnsignedByte();
+ int fieldEnd = buf.readerIndex() + (fieldLength == 255 ? buf.readUnsignedShort() : fieldLength);
- position.setAccuracy(buf.readUnsignedByte());
- position.setValid(buf.readUnsignedByte() != 0);
+ if (fieldId == 0) {
- } else if (fieldId == 2) {
+ position.setFixTime(new Date(1356998400000L + buf.readUnsignedInt() * 1000));
+ position.setLatitude(buf.readInt() * 0.0000001);
+ position.setLongitude(buf.readInt() * 0.0000001);
+ position.setAltitude(buf.readShort());
+ position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShort()));
- int input = buf.readInt();
- int output = buf.readUnsignedShort();
- int status = buf.readUnsignedShort();
+ buf.readUnsignedByte(); // speed accuracy
- position.set(Position.KEY_IGNITION, BitUtil.check(input, 0));
+ position.setCourse(buf.readUnsignedByte() * 2);
- position.set(Position.KEY_INPUT, input);
- position.set(Position.KEY_OUTPUT, output);
- position.set(Position.KEY_STATUS, status);
+ position.set(Position.KEY_PDOP, buf.readUnsignedByte() * 0.1);
- } else if (fieldId == 6) {
+ position.setAccuracy(buf.readUnsignedByte());
+ position.setValid(buf.readUnsignedByte() != 0);
- while (buf.readerIndex() < fieldEnd) {
- switch (buf.readUnsignedByte()) {
- case 1:
- position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001);
- break;
- case 2:
- position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
- break;
- case 3:
- position.set(Position.KEY_DEVICE_TEMP, buf.readShort() * 0.01);
- break;
- case 4:
- position.set(Position.KEY_RSSI, buf.readUnsignedShort());
- break;
- case 5:
- position.set("solarPower", buf.readUnsignedShort() * 0.001);
- break;
- default:
- break;
- }
- }
+ } else if (fieldId == 2) {
- }
+ int input = buf.readInt();
+ int output = buf.readUnsignedShort();
+ int status = buf.readUnsignedShort();
- buf.readerIndex(fieldEnd);
+ position.set(Position.KEY_IGNITION, BitUtil.check(input, 0));
- }
+ position.set(Position.KEY_INPUT, input);
+ position.set(Position.KEY_OUTPUT, output);
+ position.set(Position.KEY_STATUS, status);
+
+ } else if (fieldId == 6) {
+
+ while (buf.readerIndex() < fieldEnd) {
+ switch (buf.readUnsignedByte()) {
+ case 1:
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001);
+ break;
+ case 2:
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
+ break;
+ case 3:
+ position.set(Position.KEY_DEVICE_TEMP, buf.readShort() * 0.01);
+ break;
+ case 4:
+ position.set(Position.KEY_RSSI, buf.readUnsignedShort());
+ break;
+ case 5:
+ position.set("solarPower", buf.readUnsignedShort() * 0.001);
+ break;
+ default:
+ break;
+ }
+ }
- if (position.getFixTime() == null) {
- getLastLocation(position, position.getDeviceTime());
}
- positions.add(position);
+ buf.readerIndex(fieldEnd);
+
+ }
+
+ if (position.getFixTime() == null) {
+ getLastLocation(position, position.getDeviceTime());
+ }
+
+ positions.add(position);
+ }
+
+ return positions;
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+ ChannelBuffer buf = (ChannelBuffer) msg;
+
+ buf.skipBytes(2); // header
+
+ int type = buf.readUnsignedByte();
+ int length = buf.readUnsignedShort();
+
+ if (type == MSG_HELLO) {
+
+ buf.readUnsignedInt(); // device serial number
+
+ DeviceSession deviceSession = getDeviceSession(
+ channel, remoteAddress, buf.readBytes(15).toString(StandardCharsets.US_ASCII));
+
+ ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0);
+ if (length == 51) {
+ response.writeByte(0); // reserved
+ response.writeInt(0); // reserved
+ } else {
+ response.writeInt((int) ((System.currentTimeMillis() - 1356998400000L) / 1000));
+ response.writeInt(deviceSession != null ? 0 : 1); // flags
}
- return positions;
+ sendResponse(channel, MSG_HELLO_RESPONSE, response);
+
+ } else if (type == MSG_COMMIT) {
+
+ ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0);
+ response.writeByte(1); // flags (success)
+ sendResponse(channel, MSG_COMMIT_RESPONSE, response);
+
+ } else if (type == MSG_CANNED_REQUEST_1) {
+
+ ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0);
+ response.writeBytes(new byte[12]);
+ sendResponse(channel, MSG_CANNED_RESPONSE_1, response);
+
+ } else if (type == MSG_CANNED_REQUEST_2) {
+
+ sendResponse(channel, MSG_CANNED_RESPONSE_2, null);
+
+ } else if (type == MSG_DATA_RECORD_64) {
+
+ return decodeFixed64(channel, remoteAddress, buf);
+
+ } else if (type == MSG_DATA_RECORD) {
+
+ return decodeStandard(channel, remoteAddress, buf);
}
diff --git a/src/org/traccar/protocol/EelinkProtocolEncoder.java b/src/org/traccar/protocol/EelinkProtocolEncoder.java
index 76865a039..4d2d86e68 100644
--- a/src/org/traccar/protocol/EelinkProtocolEncoder.java
+++ b/src/org/traccar/protocol/EelinkProtocolEncoder.java
@@ -18,10 +18,10 @@ package org.traccar.protocol;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.traccar.BaseProtocolEncoder;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.Log;
import org.traccar.model.Command;
-import javax.xml.bind.DatatypeConverter;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
@@ -47,7 +47,7 @@ public class EelinkProtocolEncoder extends BaseProtocolEncoder {
ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
if (connectionless) {
- buf.writeBytes(ChannelBuffers.wrappedBuffer(DatatypeConverter.parseHexBinary('0' + uniqueId)));
+ buf.writeBytes(ChannelBuffers.wrappedBuffer(DataConverter.parseHex('0' + uniqueId)));
}
buf.writeByte(0x67);
diff --git a/src/org/traccar/protocol/FlespiProtocolDecoder.java b/src/org/traccar/protocol/FlespiProtocolDecoder.java
index be0e4a07f..526e10fa2 100644
--- a/src/org/traccar/protocol/FlespiProtocolDecoder.java
+++ b/src/org/traccar/protocol/FlespiProtocolDecoder.java
@@ -123,7 +123,7 @@ public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder {
return true;
case "din":
case "dout":
- position.set((name.equals("din") ? Position.KEY_INPUT : Position.KEY_OUTPUT),
+ position.set(name.equals("din") ? Position.KEY_INPUT : Position.KEY_OUTPUT,
((JsonNumber) value).intValue());
return true;
case "gps.vehicle.mileage":
diff --git a/src/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/org/traccar/protocol/Gl200TextProtocolDecoder.java
index c47764989..ff300d429 100644
--- a/src/org/traccar/protocol/Gl200TextProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gl200TextProtocolDecoder.java
@@ -429,8 +429,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
parser.next(); // odometer or external power
- position.set(Position.KEY_BATTERY, parser.nextDouble(0));
- position.set(Position.KEY_CHARGE, parser.nextInt(0) == 1);
+ position.set(Position.KEY_BATTERY, parser.nextDouble());
+ position.set(Position.KEY_CHARGE, parser.nextInt() == 1);
position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
@@ -444,7 +444,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, parser.nextDateTime());
- position.set(Position.KEY_INDEX, parser.nextHexInt(0));
+ position.set(Position.KEY_INDEX, parser.nextHexInt());
return position;
}
@@ -457,8 +457,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
}
position.set("deviceType", parser.next());
- position.set(Position.KEY_VERSION_FW, parser.nextHexInt(0));
- position.set(Position.KEY_VERSION_HW, parser.nextHexInt(0));
+ position.set(Position.KEY_VERSION_FW, parser.nextHexInt());
+ position.set(Position.KEY_VERSION_HW, parser.nextHexInt());
getLastLocation(position, parser.nextDateTime());
@@ -466,8 +466,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
}
private void decodeLocation(Position position, Parser parser) {
- int hdop = parser.nextInt(0);
- position.setValid(hdop > 0);
+ Integer hdop = parser.nextInt();
+ position.setValid(hdop == null || hdop > 0);
position.set(Position.KEY_HDOP, hdop);
position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0)));
@@ -476,25 +476,27 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
if (parser.hasNext(8)) {
position.setValid(true);
- position.setLongitude(parser.nextDouble(0));
- position.setLatitude(parser.nextDouble(0));
+ position.setLongitude(parser.nextDouble());
+ position.setLatitude(parser.nextDouble());
position.setTime(parser.nextDateTime());
} else {
getLastLocation(position, null);
}
if (parser.hasNext(6)) {
- int mcc = parser.nextInt(0);
- int mnc = parser.nextInt(0);
+ int mcc = parser.nextInt();
+ int mnc = parser.nextInt();
if (parser.hasNext(2)) {
- position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextInt(0), parser.nextInt(0))));
+ position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextInt(), parser.nextInt())));
}
if (parser.hasNext(2)) {
- position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextHexInt(0), parser.nextHexInt(0))));
+ position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt())));
}
}
- position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000);
+ if (parser.hasNext()) {
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
+ }
}
private Object decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) {
@@ -509,16 +511,22 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.PREFIX_TEMP + 1, parser.nextInt());
position.set(Position.KEY_FUEL_CONSUMPTION, parser.next());
position.set("dtcsClearedDistance", parser.nextInt());
- position.set("odbConnect", parser.nextInt(0) == 1);
+ if (parser.hasNext()) {
+ position.set("odbConnect", parser.nextInt() == 1);
+ }
position.set("dtcsNumber", parser.nextInt());
position.set("dtcsCodes", parser.next());
position.set(Position.KEY_THROTTLE, parser.nextInt());
position.set(Position.KEY_FUEL_LEVEL, parser.nextInt());
- position.set(Position.KEY_OBD_ODOMETER, parser.nextInt(0) * 1000);
+ if (parser.hasNext()) {
+ position.set(Position.KEY_OBD_ODOMETER, parser.nextInt() * 1000);
+ }
decodeLocation(position, parser);
- position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000);
+ if (parser.hasNext()) {
+ position.set(Position.KEY_OBD_ODOMETER, (int) (parser.nextDouble() * 1000));
+ }
decodeDeviceTime(position, parser);
@@ -649,14 +657,14 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
private void decodeStatus(Position position, Parser parser) {
if (parser.hasNext(3)) {
- int ignition = parser.nextHexInt(0);
+ int ignition = parser.nextHexInt();
if (BitUtil.check(ignition, 4)) {
position.set(Position.KEY_IGNITION, false);
} else if (BitUtil.check(ignition, 5)) {
position.set(Position.KEY_IGNITION, true);
}
- position.set(Position.KEY_INPUT, parser.nextHexInt(0));
- position.set(Position.KEY_OUTPUT, parser.nextHexInt(0));
+ position.set(Position.KEY_INPUT, parser.nextHexInt());
+ position.set(Position.KEY_OUTPUT, parser.nextHexInt());
}
}
@@ -674,7 +682,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
LinkedList<Position> positions = new LinkedList<>();
String vin = parser.next();
- int power = parser.nextInt(0);
+ Integer power = parser.nextInt();
Parser itemParser = new Parser(PATTERN_LOCATION, parser.next());
while (itemParser.find()) {
@@ -692,14 +700,18 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
decodeLocation(position, parser);
- if (power > 10) {
+ if (power != null && power > 10) {
position.set(Position.KEY_POWER, power * 0.001); // only on some devices
}
- position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000);
+ if (parser.hasNext()) {
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
+ }
position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
- position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000);
+ if (parser.hasNext()) {
+ 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());
@@ -734,7 +746,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
LinkedList<Position> positions = new LinkedList<>();
- int power = parser.nextInt(0);
+ Integer power = parser.nextInt();
Parser itemParser = new Parser(PATTERN_LOCATION, parser.next());
while (itemParser.find()) {
@@ -750,8 +762,10 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
decodeLocation(position, parser);
- position.set(Position.KEY_POWER, power * 0.001);
- position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000);
+ if (power != null) {
+ position.set(Position.KEY_POWER, power * 0.001);
+ }
+ 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());
@@ -773,7 +787,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
for (int i = 1; i <= deviceCount; i++) {
index += 1; // id
index += 1; // type
- position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(data[index++], 16) * 0.0625);
+ if (!data[index++].isEmpty()) {
+ position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(data[index - 1], 16) * 0.0625);
+ }
}
}
@@ -813,7 +829,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
decodeLocation(position, parser);
position.set(Position.KEY_HOURS, parser.next());
- position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000);
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
decodeDeviceTime(position, parser);
@@ -831,7 +847,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
decodeLocation(position, parser);
- position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000);
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
decodeDeviceTime(position, parser);
@@ -849,7 +865,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
Network network = new Network();
- parser.nextInt(0); // count
+ parser.nextInt(); // count
Matcher matcher = Pattern.compile("([0-9a-fA-F]{12}),(-?\\d+),,,,").matcher(parser.next());
while (matcher.find()) {
String mac = matcher.group(1).replaceAll("(..)", "$1:");
@@ -859,7 +875,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
position.setNetwork(network);
- position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0));
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
return position;
}
@@ -897,7 +913,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- int reportType = parser.nextInt(0);
+ int reportType = parser.nextInt();
if (type.equals("NMR")) {
position.set(Position.KEY_MOTION, reportType == 1);
} else if (type.equals("SOS")) {
@@ -906,10 +922,14 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
decodeLocation(position, parser);
- position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000);
- position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0));
+ if (parser.hasNext()) {
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
+ }
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
- position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000);
+ if (parser.hasNext()) {
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
+ }
decodeDeviceTime(position, parser);
@@ -927,7 +947,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- int hdop = parser.nextInt(0);
+ int hdop = parser.nextInt();
position.setValid(hdop > 0);
position.set(Position.KEY_HDOP, hdop);
@@ -936,8 +956,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
position.setAltitude(parser.nextDouble(0));
if (parser.hasNext(2)) {
- position.setLongitude(parser.nextDouble(0));
- position.setLatitude(parser.nextDouble(0));
+ position.setLongitude(parser.nextDouble());
+ position.setLatitude(parser.nextDouble());
} else {
getLastLocation(position, null);
}
@@ -948,7 +968,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
if (parser.hasNext(4)) {
position.setNetwork(new Network(CellTower.from(
- parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0))));
+ parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt())));
}
decodeDeviceTime(position, parser);
diff --git a/src/org/traccar/protocol/HuabaoProtocolEncoder.java b/src/org/traccar/protocol/HuabaoProtocolEncoder.java
index 7d6f0510d..d1889bf5e 100644
--- a/src/org/traccar/protocol/HuabaoProtocolEncoder.java
+++ b/src/org/traccar/protocol/HuabaoProtocolEncoder.java
@@ -18,10 +18,10 @@ package org.traccar.protocol;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.traccar.BaseProtocolEncoder;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.Log;
import org.traccar.model.Command;
-import javax.xml.bind.DatatypeConverter;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -31,10 +31,10 @@ public class HuabaoProtocolEncoder extends BaseProtocolEncoder {
protected Object encodeCommand(Command command) {
ChannelBuffer id = ChannelBuffers.wrappedBuffer(
- DatatypeConverter.parseHexBinary(getUniqueId(command.getDeviceId())));
+ DataConverter.parseHex(getUniqueId(command.getDeviceId())));
ChannelBuffer data = ChannelBuffers.dynamicBuffer();
- byte[] time = DatatypeConverter.parseHexBinary(new SimpleDateFormat("yyMMddHHmmss").format(new Date()));
+ byte[] time = DataConverter.parseHex(new SimpleDateFormat("yyMMddHHmmss").format(new Date()));
switch (command.getType()) {
case Command.TYPE_ENGINE_STOP:
diff --git a/src/org/traccar/protocol/MeiligaoProtocolEncoder.java b/src/org/traccar/protocol/MeiligaoProtocolEncoder.java
index 2e0a1e84c..340d947e3 100644
--- a/src/org/traccar/protocol/MeiligaoProtocolEncoder.java
+++ b/src/org/traccar/protocol/MeiligaoProtocolEncoder.java
@@ -19,10 +19,10 @@ import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.traccar.BaseProtocolEncoder;
import org.traccar.helper.Checksum;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.Log;
import org.traccar.model.Command;
-import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;
import java.util.TimeZone;
@@ -44,7 +44,7 @@ public class MeiligaoProtocolEncoder extends BaseProtocolEncoder {
buf.writeShort(2 + 2 + 7 + 2 + content.readableBytes() + 2 + 2); // message length
- buf.writeBytes(DatatypeConverter.parseHexBinary((getUniqueId(deviceId) + "FFFFFFFFFFFFFF").substring(0, 14)));
+ buf.writeBytes(DataConverter.parseHex((getUniqueId(deviceId) + "FFFFFFFFFFFFFF").substring(0, 14)));
buf.writeShort(type);
diff --git a/src/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/org/traccar/protocol/RuptelaProtocolDecoder.java
index 87ee8246a..7b11cc5c3 100644
--- a/src/org/traccar/protocol/RuptelaProtocolDecoder.java
+++ b/src/org/traccar/protocol/RuptelaProtocolDecoder.java
@@ -20,10 +20,10 @@ import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
-import javax.xml.bind.DatatypeConverter;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Date;
@@ -196,7 +196,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
}
if (channel != null) {
- channel.write(ChannelBuffers.wrappedBuffer(DatatypeConverter.parseHexBinary("0002640113bc")));
+ channel.write(ChannelBuffers.wrappedBuffer(DataConverter.parseHex("0002640113bc")));
}
return positions;
@@ -229,7 +229,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
}
if (channel != null) {
- channel.write(ChannelBuffers.wrappedBuffer(DatatypeConverter.parseHexBinary("00026d01c4a4")));
+ channel.write(ChannelBuffers.wrappedBuffer(DataConverter.parseHex("00026d01c4a4")));
}
return positions;
diff --git a/src/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/org/traccar/protocol/SigfoxProtocolDecoder.java
index 65ab2cc55..b454e00fa 100644
--- a/src/org/traccar/protocol/SigfoxProtocolDecoder.java
+++ b/src/org/traccar/protocol/SigfoxProtocolDecoder.java
@@ -22,12 +22,12 @@ import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.traccar.BaseHttpProtocolDecoder;
import org.traccar.DeviceSession;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
import javax.json.Json;
import javax.json.JsonObject;
-import javax.xml.bind.DatatypeConverter;
import java.io.StringReader;
import java.net.SocketAddress;
import java.net.URLDecoder;
@@ -61,7 +61,7 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder {
position.setTime(new Date(json.getInt("time") * 1000L));
ChannelBuffer buf = ChannelBuffers.wrappedBuffer(
- ByteOrder.LITTLE_ENDIAN, DatatypeConverter.parseHexBinary(json.getString("data")));
+ ByteOrder.LITTLE_ENDIAN, DataConverter.parseHex(json.getString("data")));
int type = buf.readUnsignedByte() >> 4;
if (type == 0) {
diff --git a/src/org/traccar/protocol/T55ProtocolDecoder.java b/src/org/traccar/protocol/T55ProtocolDecoder.java
index dbc467993..be3cb5f67 100644
--- a/src/org/traccar/protocol/T55ProtocolDecoder.java
+++ b/src/org/traccar/protocol/T55ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2018 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.
@@ -250,9 +250,11 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
} else if (sentence.startsWith("$PCPTI")) {
getDeviceSession(channel, remoteAddress, sentence.substring(7, sentence.indexOf(",", 7)));
} else if (sentence.startsWith("IMEI")) {
- getDeviceSession(channel, remoteAddress, sentence.substring(5, sentence.length()));
+ getDeviceSession(channel, remoteAddress, sentence.substring(5));
+ } else if (sentence.startsWith("$IMEI")) {
+ getDeviceSession(channel, remoteAddress, sentence.substring(6));
} else if (sentence.startsWith("$GPFID")) {
- deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(7, sentence.length()));
+ deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(7));
if (deviceSession != null && position != null) {
Position position = this.position;
position.setDeviceId(deviceSession.getDeviceId());
diff --git a/src/org/traccar/protocol/T800xProtocolEncoder.java b/src/org/traccar/protocol/T800xProtocolEncoder.java
index 6ed5dbccd..038a5e51a 100644
--- a/src/org/traccar/protocol/T800xProtocolEncoder.java
+++ b/src/org/traccar/protocol/T800xProtocolEncoder.java
@@ -18,10 +18,10 @@ package org.traccar.protocol;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.traccar.BaseProtocolEncoder;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.Log;
import org.traccar.model.Command;
-import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;
public class T800xProtocolEncoder extends BaseProtocolEncoder {
@@ -39,7 +39,7 @@ public class T800xProtocolEncoder extends BaseProtocolEncoder {
buf.writeByte(T800xProtocolDecoder.MSG_COMMAND);
buf.writeShort(7 + 8 + 1 + content.length());
buf.writeShort(1); // serial number
- buf.writeBytes(DatatypeConverter.parseHexBinary("0" + getUniqueId(command.getDeviceId())));
+ buf.writeBytes(DataConverter.parseHex("0" + getUniqueId(command.getDeviceId())));
buf.writeByte(MODE_SETTING);
buf.writeBytes(content.getBytes(StandardCharsets.US_ASCII));
diff --git a/src/org/traccar/protocol/TaipProtocolDecoder.java b/src/org/traccar/protocol/TaipProtocolDecoder.java
index 9555d19e9..a7aa9dd96 100644
--- a/src/org/traccar/protocol/TaipProtocolDecoder.java
+++ b/src/org/traccar/protocol/TaipProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2018 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.
@@ -62,16 +62,23 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
.number("(ddd)") // speed
.number("(ddd)") // course
.groupBegin()
+ .number("([023])") // fix mode
+ .number("xx") // data age
+ .number("(xx)") // input
+ .number("(dd)") // event
+ .number("(dd)") // hdop
+ .or()
+ .groupBegin()
.number("(xx)") // input
.number("(xx)") // satellites
.number("(ddd)") // battery
.number("(x{8})") // odometer
.number("[01]") // gps power
.groupBegin()
- .number("[23]") // fix mode
+ .number("([023])") // fix mode
.number("(dd)") // pdop
.number("dd") // satellites
- .number("xxxx") // seconds from last
+ .number("xxxx") // data age
.number("[01]") // modem power
.number("[0-5]") // gsm status
.number("(dd)") // rssi
@@ -81,6 +88,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
.number("xx") // seconds from last
.groupEnd("?")
.groupEnd("?")
+ .groupEnd()
.any()
.compile();
@@ -116,6 +124,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position(getProtocolName());
+ Boolean valid = null;
Integer event = null;
if (parser.hasNext(3)) {
@@ -129,27 +138,6 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
event = parser.nextInt();
}
- if (event != null) {
- switch (event) {
- case 22:
- position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
- break;
- case 23:
- position.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
- break;
- case 24:
- position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT);
- break;
- case 26:
- case 28:
- position.set(Position.KEY_ALARM, Position.ALARM_CORNERING);
- break;
- default:
- position.set(Position.KEY_EVENT, event);
- break;
- }
- }
-
if (parser.hasNext(6)) {
position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
}
@@ -167,6 +155,15 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
position.setCourse(parser.nextDouble(0));
if (parser.hasNext(4)) {
+ valid = parser.nextInt() > 0;
+ int input = parser.nextHexInt();
+ position.set(Position.KEY_IGNITION, BitUtil.check(input, 7));
+ position.set(Position.KEY_INPUT, input);
+ event = parser.nextInt();
+ position.set(Position.KEY_HDOP, parser.nextInt());
+ }
+
+ if (parser.hasNext(4)) {
position.set(Position.KEY_INPUT, parser.nextHexInt(0));
position.set(Position.KEY_SATELLITES, parser.nextHexInt(0));
position.set(Position.KEY_BATTERY, parser.nextInt(0));
@@ -174,13 +171,35 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
}
if (parser.hasNext(4)) {
+ valid = parser.nextInt() > 0;
position.set(Position.KEY_PDOP, parser.nextInt());
position.set(Position.KEY_RSSI, parser.nextInt());
position.set(Position.PREFIX_TEMP + 1, parser.nextInt() * 0.01);
position.set(Position.PREFIX_TEMP + 2, parser.nextInt() * 0.01);
}
- position.setValid(true);
+ position.setValid(valid != null ? valid : true);
+
+ if (event != null) {
+ position.set(Position.KEY_EVENT, event);
+ switch (event) {
+ case 22:
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
+ break;
+ case 23:
+ position.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
+ break;
+ case 24:
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT);
+ break;
+ case 26:
+ case 28:
+ position.set(Position.KEY_ALARM, Position.ALARM_CORNERING);
+ break;
+ default:
+ break;
+ }
+ }
String[] attributes = null;
beginIndex = sentence.indexOf(';');
@@ -250,14 +269,13 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
if (deviceSession != null) {
if (channel != null) {
if (messageIndex != null) {
- String response = ">ACK;" + messageIndex + ";ID=" + uniqueId + ";*";
+ String response = ">ACK;ID=" + uniqueId + ";" + messageIndex + ";*";
response += String.format("%02X", Checksum.xor(response)) + "<";
channel.write(response, remoteAddress);
} else {
channel.write(uniqueId, remoteAddress);
}
}
-
return position;
}
diff --git a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
index 9e249247a..d2069e6c9 100644
--- a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
+++ b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2018 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.
@@ -133,7 +133,10 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.PREFIX_TEMP + 3, readValue(buf, length, true) * 0.1);
break;
case 78:
- position.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", readValue(buf, length, false)));
+ long driverUniqueId = readValue(buf, length, false);
+ if (driverUniqueId != 0) {
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", driverUniqueId));
+ }
break;
case 80:
position.set("workMode", readValue(buf, length, false));
diff --git a/src/org/traccar/protocol/WatchProtocolDecoder.java b/src/org/traccar/protocol/WatchProtocolDecoder.java
index 1dd07a3f7..c57279296 100644
--- a/src/org/traccar/protocol/WatchProtocolDecoder.java
+++ b/src/org/traccar/protocol/WatchProtocolDecoder.java
@@ -97,8 +97,38 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- private void decodeTail(Position position, String data) {
- String[] values = data.split(",");
+ private Position decodePosition(DeviceSession deviceSession, String data) {
+
+ Parser parser = new Parser(PATTERN_POSITION, data);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0)));
+ position.setCourse(parser.nextDouble(0));
+ position.setAltitude(parser.nextDouble(0));
+
+ position.set(Position.KEY_SATELLITES, parser.nextInt(0));
+ position.set(Position.KEY_RSSI, parser.nextInt(0));
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0));
+
+ position.set(Position.KEY_STEPS, parser.nextInt(0));
+
+ int status = parser.nextHexInt(0);
+ position.set(Position.KEY_ALARM, decodeAlarm(status));
+ if (BitUtil.check(status, 4)) {
+ position.set(Position.KEY_MOTION, true);
+ }
+
+ String[] values = parser.next().split(",");
int index = 0;
Network network = new Network();
@@ -127,6 +157,8 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) {
position.setNetwork(network);
}
+
+ return position;
}
@Override
@@ -171,7 +203,11 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
buf.readerIndex(contentIndex + 1);
}
- if (type.equals("LK")) {
+ if (type.equals("INIT")) {
+
+ sendResponse(channel, manufacturer, id, index, "INIT,1");
+
+ } else if (type.equals("LK")) {
sendResponse(channel, manufacturer, id, index, "LK");
@@ -196,44 +232,13 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
sendResponse(channel, manufacturer, id, index, "AL");
}
- Parser parser = new Parser(PATTERN_POSITION, buf.toString(StandardCharsets.US_ASCII));
- if (!parser.matches()) {
- return null;
- }
-
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
-
- position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
-
- position.setValid(parser.next().equals("A"));
- position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
- position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
- position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0)));
- position.setCourse(parser.nextDouble(0));
- position.setAltitude(parser.nextDouble(0));
-
- position.set(Position.KEY_SATELLITES, parser.nextInt(0));
- position.set(Position.KEY_RSSI, parser.nextInt(0));
- position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0));
-
- position.set(Position.KEY_STEPS, parser.nextInt(0));
-
- int status = parser.nextHexInt(0);
- position.set(Position.KEY_ALARM, decodeAlarm(status));
- if (BitUtil.check(status, 4)) {
- position.set(Position.KEY_MOTION, true);
- }
-
- decodeTail(position, parser.next());
-
- return position;
+ return decodePosition(deviceSession, buf.toString(StandardCharsets.US_ASCII));
} else if (type.equals("TKQ")) {
sendResponse(channel, manufacturer, id, index, "TKQ");
- } else if (type.equals("PULSE") || type.equals("heart")) {
+ } else if (type.equals("PULSE") || type.equals("heart") || type.equals("bphrt")) {
if (buf.readable()) {
@@ -242,10 +247,14 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, new Date());
- position.setValid(false);
- String pulse = buf.toString(StandardCharsets.US_ASCII);
- position.set("pulse", pulse);
- position.set(Position.KEY_RESULT, pulse);
+ String[] values = buf.toString(StandardCharsets.US_ASCII).split(",");
+ int valueIndex = 0;
+
+ if (type.equals("bphrt")) {
+ position.set("pressureHigh", values[valueIndex++]);
+ position.set("pressureLow", values[valueIndex++]);
+ }
+ position.set("pulse", values[valueIndex]);
return position;
diff --git a/src/org/traccar/protocol/WatchProtocolEncoder.java b/src/org/traccar/protocol/WatchProtocolEncoder.java
index d2d3b52d1..5206fbf10 100644
--- a/src/org/traccar/protocol/WatchProtocolEncoder.java
+++ b/src/org/traccar/protocol/WatchProtocolEncoder.java
@@ -16,10 +16,10 @@
package org.traccar.protocol;
import org.traccar.StringProtocolEncoder;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.Log;
import org.traccar.model.Command;
-import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
@@ -68,7 +68,7 @@ public class WatchProtocolEncoder extends StringProtocolEncoder implements Strin
}
private String getBinaryData(Command command) {
- byte[] data = DatatypeConverter.parseHexBinary(command.getString(Command.KEY_DATA));
+ byte[] data = DataConverter.parseHex(command.getString(Command.KEY_DATA));
int encodedLength = data.length;
for (byte b : data) {
diff --git a/src/org/traccar/protocol/XirgoProtocolDecoder.java b/src/org/traccar/protocol/XirgoProtocolDecoder.java
index 10dd298fd..461503af1 100644
--- a/src/org/traccar/protocol/XirgoProtocolDecoder.java
+++ b/src/org/traccar/protocol/XirgoProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2018 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.
@@ -95,6 +95,71 @@ public class XirgoProtocolDecoder extends BaseProtocolDecoder {
.any()
.compile();
+ private void decodeEvent(Position position, int event) {
+
+ position.set(Position.KEY_EVENT, event);
+
+ switch (event) {
+ case 4001:
+ case 4003:
+ case 6011:
+ case 6013:
+ position.set(Position.KEY_IGNITION, true);
+ break;
+ case 4002:
+ case 4004:
+ case 6012:
+ case 6014:
+ position.set(Position.KEY_IGNITION, false);
+ break;
+ case 4005:
+ position.set(Position.KEY_CHARGE, false);
+ break;
+ case 6002:
+ position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED);
+ break;
+ case 6006:
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
+ break;
+ case 6007:
+ position.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
+ break;
+ case 6008:
+ position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER);
+ break;
+ case 6009:
+ position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT);
+ break;
+ case 6010:
+ position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED);
+ break;
+ case 6016:
+ position.set(Position.KEY_ALARM, Position.ALARM_IDLE);
+ break;
+ case 6017:
+ position.set(Position.KEY_ALARM, Position.ALARM_TOW);
+ break;
+ case 6030:
+ case 6071:
+ position.set(Position.KEY_MOTION, true);
+ break;
+ case 6031:
+ position.set(Position.KEY_MOTION, false);
+ break;
+ case 6032:
+ position.set(Position.KEY_ALARM, Position.ALARM_PARKING);
+ break;
+ case 6090:
+ position.set(Position.KEY_ALARM, Position.ALARM_REMOVING);
+ break;
+ case 6091:
+ position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
+ break;
+ default:
+ break;
+ }
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -133,7 +198,7 @@ public class XirgoProtocolDecoder extends BaseProtocolDecoder {
}
position.setDeviceId(deviceSession.getDeviceId());
- position.set(Position.KEY_EVENT, parser.next());
+ decodeEvent(position, parser.nextInt());
position.setTime(parser.nextDateTime());
diff --git a/src/org/traccar/protocol/Xt2400ProtocolDecoder.java b/src/org/traccar/protocol/Xt2400ProtocolDecoder.java
index 72be473c1..1be943e98 100644
--- a/src/org/traccar/protocol/Xt2400ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Xt2400ProtocolDecoder.java
@@ -20,10 +20,10 @@ import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.Context;
import org.traccar.DeviceSession;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
-import javax.xml.bind.DatatypeConverter;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Date;
@@ -95,7 +95,7 @@ public class Xt2400ProtocolDecoder extends BaseProtocolDecoder {
Pattern pattern = Pattern.compile(":wycfg pcr\\[\\d+\\] ([0-9a-fA-F]{2})[0-9a-fA-F]{2}([0-9a-fA-F]+)");
Matcher matcher = pattern.matcher(configString);
while (matcher.find()) {
- formats.put(Short.parseShort(matcher.group(1), 16), DatatypeConverter.parseHexBinary(matcher.group(2)));
+ formats.put(Short.parseShort(matcher.group(1), 16), DataConverter.parseHex(matcher.group(2)));
}
}