aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--setup/default.xml5
-rw-r--r--src/org/traccar/database/StatisticsManager.java6
-rw-r--r--src/org/traccar/helper/Parser.java16
-rw-r--r--src/org/traccar/processing/ComputedAttributesHandler.java2
-rw-r--r--src/org/traccar/protocol/DwayProtocolDecoder.java15
-rw-r--r--src/org/traccar/protocol/Gt06ProtocolDecoder.java79
-rw-r--r--src/org/traccar/protocol/MeiligaoProtocolDecoder.java153
-rw-r--r--src/org/traccar/protocol/Pt502FrameDecoder.java11
-rw-r--r--src/org/traccar/protocol/Pt502Protocol.java3
-rw-r--r--src/org/traccar/protocol/Pt502ProtocolDecoder.java4
-rw-r--r--src/org/traccar/protocol/Pt502ProtocolEncoder.java2
-rw-r--r--src/org/traccar/protocol/RecodaProtocol.java46
-rw-r--r--src/org/traccar/protocol/RecodaProtocolDecoder.java110
-rw-r--r--test/org/traccar/processing/ComputedAttributesTest.java17
-rw-r--r--test/org/traccar/protocol/DwayProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/Gt06FrameDecoderTest.java20
-rw-r--r--test/org/traccar/protocol/Gt06ProtocolDecoderTest.java24
-rw-r--r--test/org/traccar/protocol/MeiligaoProtocolDecoderTest.java9
-rw-r--r--test/org/traccar/protocol/Pt502FrameDecoderTest.java12
-rw-r--r--test/org/traccar/protocol/Pt502ProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/Pt502ProtocolEncoderTest.java14
-rw-r--r--test/org/traccar/protocol/RecodaProtocolDecoderTest.java26
22 files changed, 462 insertions, 121 deletions
diff --git a/setup/default.xml b/setup/default.xml
index d33e6dd27..8b8e0d623 100644
--- a/setup/default.xml
+++ b/setup/default.xml
@@ -219,7 +219,8 @@
<entry key='genx.port'>5148</entry>
<entry key='flespi.port'>5149</entry>
<entry key='dway.port'>5150</entry>
- <entry key='arnavi4.port'>5151</entry>
-
+ <entry key='recoda.port'>5151</entry>
+ <entry key='arnavi4.port'>5152</entry>
+
</properties>
diff --git a/src/org/traccar/database/StatisticsManager.java b/src/org/traccar/database/StatisticsManager.java
index 06a3e7b35..9a3ff06bd 100644
--- a/src/org/traccar/database/StatisticsManager.java
+++ b/src/org/traccar/database/StatisticsManager.java
@@ -27,12 +27,13 @@ import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
public class StatisticsManager {
private static final int SPLIT_MODE = Calendar.DAY_OF_MONTH;
- private int lastUpdate = Calendar.getInstance().get(SPLIT_MODE);
+ private AtomicInteger lastUpdate = new AtomicInteger(Calendar.getInstance().get(SPLIT_MODE));
private Set<Long> users = new HashSet<>();
private Set<Long> devices = new HashSet<>();
@@ -47,7 +48,7 @@ public class StatisticsManager {
private void checkSplit() {
int currentUpdate = Calendar.getInstance().get(SPLIT_MODE);
- if (lastUpdate != currentUpdate) {
+ if (lastUpdate.getAndSet(currentUpdate) != currentUpdate) {
Statistics statistics = new Statistics();
statistics.setCaptureTime(new Date());
statistics.setActiveUsers(users.size());
@@ -96,7 +97,6 @@ public class StatisticsManager {
smsSent = 0;
geocoderRequests = 0;
geolocationRequests = 0;
- lastUpdate = currentUpdate;
}
}
diff --git a/src/org/traccar/helper/Parser.java b/src/org/traccar/helper/Parser.java
index 582b497cf..1471ec237 100644
--- a/src/org/traccar/helper/Parser.java
+++ b/src/org/traccar/helper/Parser.java
@@ -109,6 +109,22 @@ public class Parser {
}
}
+ public Long nextLong() {
+ if (hasNext()) {
+ return Long.parseLong(next());
+ } else {
+ return null;
+ }
+ }
+
+ public Long nextHexLong() {
+ if (hasNext()) {
+ return Long.parseLong(next(), 16);
+ } else {
+ return null;
+ }
+ }
+
public long nextLong(long defaultValue) {
return nextLong(10, defaultValue);
}
diff --git a/src/org/traccar/processing/ComputedAttributesHandler.java b/src/org/traccar/processing/ComputedAttributesHandler.java
index f1f371475..1e702d17f 100644
--- a/src/org/traccar/processing/ComputedAttributesHandler.java
+++ b/src/org/traccar/processing/ComputedAttributesHandler.java
@@ -20,6 +20,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -43,6 +44,7 @@ public class ComputedAttributesHandler extends BaseDataHandler {
public ComputedAttributesHandler() {
engine = new JexlEngine();
engine.setStrict(true);
+ engine.setFunctions(Collections.singletonMap("math", (Object) Math.class));
if (Context.getConfig() != null) {
mapDeviceAttributes = Context.getConfig().getBoolean("processing.computedAttributes.deviceAttributes");
}
diff --git a/src/org/traccar/protocol/DwayProtocolDecoder.java b/src/org/traccar/protocol/DwayProtocolDecoder.java
index 993aa91b2..767b35c72 100644
--- a/src/org/traccar/protocol/DwayProtocolDecoder.java
+++ b/src/org/traccar/protocol/DwayProtocolDecoder.java
@@ -42,15 +42,16 @@ public class DwayProtocolDecoder extends BaseProtocolDecoder {
.number("(-?d+.d+),") // latitude
.number("(-?d+.d+),") // longitude
.number("(-?d+),") // altitude
- .number("(d+.d+),") // speed
+ .number(" ?(d+.d+),") // speed
.number("(d+),") // course
.number("([01]{4}),") // input
.number("([01]{4}),") // output
- .number("([01])([01])([01])([01]),") // flags
+ .number("([01]+),") // flags
.number("(d+),") // battery
.number("(d+),") // adc1
.number("(d+),") // adc2
.number("(d+)") // driver
+ .any()
.compile();
@Override
@@ -79,6 +80,7 @@ public class DwayProtocolDecoder extends BaseProtocolDecoder {
position.setProtocol(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
+ position.setValid(true);
position.setTime(parser.nextDateTime());
position.setLatitude(parser.nextDouble());
position.setLongitude(parser.nextDouble());
@@ -89,15 +91,6 @@ public class DwayProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_INPUT, parser.nextBinInt());
position.set(Position.KEY_OUTPUT, parser.nextBinInt());
- position.setValid(parser.next().equals("1"));
-
- position.set(Position.KEY_IGNITION, parser.next().equals("1"));
- position.set(Position.KEY_CHARGE, parser.next().equals("1"));
-
- if (parser.next().equals("1")) {
- position.set(Position.KEY_ALARM, Position.ALARM_SHOCK);
- }
-
position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001);
position.set(Position.PREFIX_ADC + 1, parser.nextInt() * 0.001);
position.set(Position.PREFIX_ADC + 2, parser.nextInt() * 0.001);
diff --git a/src/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/org/traccar/protocol/Gt06ProtocolDecoder.java
index fbd1adfc6..177c0b653 100644
--- a/src/org/traccar/protocol/Gt06ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gt06ProtocolDecoder.java
@@ -21,6 +21,7 @@ import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.Context;
import org.traccar.DeviceSession;
+import org.traccar.helper.BcdUtil;
import org.traccar.helper.BitUtil;
import org.traccar.helper.Checksum;
import org.traccar.helper.DateBuilder;
@@ -67,6 +68,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_SATELLITE = 0x14;
public static final int MSG_STRING = 0x15;
public static final int MSG_GPS_LBS_STATUS_1 = 0x16;
+ public static final int MSG_WIFI = 0x17;
public static final int MSG_GPS_LBS_STATUS_2 = 0x26;
public static final int MSG_GPS_LBS_STATUS_3 = 0x27;
public static final int MSG_LBS_MULTIPLE = 0x28;
@@ -81,6 +83,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_X1_GPS = 0x34;
public static final int MSG_X1_PHOTO_INFO = 0x35;
public static final int MSG_X1_PHOTO_DATA = 0x36;
+ public static final int MSG_WIFI_2 = 0x69;
public static final int MSG_COMMAND_0 = 0x80;
public static final int MSG_COMMAND_1 = 0x81;
public static final int MSG_COMMAND_2 = 0x82;
@@ -107,17 +110,21 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
|| type == MSG_GPS_LBS_STATUS_1 || type == MSG_GPS_LBS_STATUS_2 || type == MSG_GPS_LBS_STATUS_3;
}
- private void sendResponse(Channel channel, boolean extended, int type) {
+ private void sendResponse(Channel channel, boolean extended, int type, ChannelBuffer content) {
if (channel != null) {
ChannelBuffer response = ChannelBuffers.dynamicBuffer();
+ int length = 5 + (content != null ? content.readableBytes() : 0);
if (extended) {
response.writeShort(0x7979);
- response.writeShort(5);
+ response.writeShort(length);
} else {
response.writeShort(0x7878);
- response.writeByte(5);
+ response.writeByte(length);
}
response.writeByte(type);
+ if (content != null) {
+ response.writeBytes(content);
+ }
response.writeShort(++serverIndex);
response.writeShort(Checksum.crc16(Checksum.CRC16_X25,
response.toByteBuffer(2, response.writerIndex() - 2)));
@@ -127,21 +134,12 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
}
private void sendPhotoRequest(Channel channel, int pictureId) {
- if (channel != null) {
- ChannelBuffer photo = photos.get(pictureId);
- ChannelBuffer response = ChannelBuffers.dynamicBuffer();
- response.writeShort(0x7878); // header
- response.writeByte(15); // size
- response.writeByte(MSG_X1_PHOTO_DATA);
- response.writeInt(pictureId);
- response.writeInt(photo.writerIndex());
- response.writeShort(Math.min(photo.writableBytes(), 1024));
- response.writeShort(++serverIndex);
- response.writeShort(Checksum.crc16(Checksum.CRC16_X25,
- response.toByteBuffer(2, response.writerIndex() - 2)));
- response.writeByte('\r'); response.writeByte('\n'); // ending
- channel.write(response);
- }
+ ChannelBuffer photo = photos.get(pictureId);
+ ChannelBuffer content = ChannelBuffers.dynamicBuffer();
+ content.writeInt(pictureId);
+ content.writeInt(photo.writerIndex());
+ content.writeShort(Math.min(photo.writableBytes(), 1024));
+ sendResponse(channel, false, MSG_X1_PHOTO_DATA, content);
}
private boolean decodeGps(Position position, ChannelBuffer buf, boolean hasLength) {
@@ -347,7 +345,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
}
if (getDeviceSession(channel, remoteAddress, imei) != null) {
- sendResponse(channel, false, type);
+ sendResponse(channel, false, type, null);
}
} else if (type == MSG_X1_GPS) {
@@ -385,6 +383,43 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
photos.put(pictureId, photo);
sendPhotoRequest(channel, pictureId);
+ } else if (type == MSG_WIFI || type == MSG_WIFI_2) {
+
+ Position position = new Position();
+ position.setDeviceId(deviceSession.getDeviceId());
+ position.setProtocol(getProtocolName());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setYear(BcdUtil.readInteger(buf, 2))
+ .setMonth(BcdUtil.readInteger(buf, 2))
+ .setDay(BcdUtil.readInteger(buf, 2))
+ .setHour(BcdUtil.readInteger(buf, 2))
+ .setMinute(BcdUtil.readInteger(buf, 2))
+ .setSecond(BcdUtil.readInteger(buf, 2));
+ getLastLocation(position, dateBuilder.getDate());
+
+ Network network = new Network();
+
+ int wifiCount = buf.getByte(2);
+ for (int i = 0; i < wifiCount; i++) {
+ String mac = String.format("%02x:%02x:%02x:%02x:%02x:%02x",
+ buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte(),
+ buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ network.addWifiAccessPoint(WifiAccessPoint.from(mac, buf.readUnsignedByte()));
+ }
+
+ int cellCount = buf.readUnsignedByte();
+ int mcc = buf.readUnsignedShort();
+ int mnc = buf.readUnsignedByte();
+ for (int i = 0; i < cellCount; i++) {
+ network.addCellTower(CellTower.from(
+ mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedByte()));
+ }
+
+ position.setNetwork(network);
+
+ return position;
+
} else {
return decodeBasicOther(channel, buf, deviceSession, type, dataLength);
@@ -476,13 +511,13 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
buf.skipBytes(dataLength);
if (type != MSG_COMMAND_0 && type != MSG_COMMAND_1 && type != MSG_COMMAND_2) {
- sendResponse(channel, false, type);
+ sendResponse(channel, false, type, null);
}
return null;
}
- sendResponse(channel, false, type);
+ sendResponse(channel, false, type, null);
return position;
}
@@ -602,7 +637,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
buf.skipBytes(buf.readUnsignedByte()); // reserved extension
- sendResponse(channel, true, type);
+ sendResponse(channel, true, type, null);
return position;
diff --git a/src/org/traccar/protocol/MeiligaoProtocolDecoder.java b/src/org/traccar/protocol/MeiligaoProtocolDecoder.java
index e41a42843..b0793037f 100644
--- a/src/org/traccar/protocol/MeiligaoProtocolDecoder.java
+++ b/src/org/traccar/protocol/MeiligaoProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 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.
@@ -30,6 +30,8 @@ import org.traccar.model.Position;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
+import java.util.LinkedList;
+import java.util.List;
import java.util.regex.Pattern;
public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
@@ -55,11 +57,19 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
.number("|(xxxx)?") // state
.groupBegin()
.number("|(xxxx),(xxxx)") // adc
- .number("(?:,(xxxx),(xxxx),(xxxx),(xxxx),(xxxx),(xxxx))?")
+ .number(",(xxxx)").optional()
+ .number(",(xxxx)").optional()
+ .number(",(xxxx)").optional()
+ .number(",(xxxx)").optional()
+ .number(",(xxxx)").optional()
+ .number(",(xxxx)").optional()
.groupBegin()
- .number("|x{16}") // cell
- .number("|(xx)") // gsm
+ .number("|x{16,20}") // cell
+ .number("|(xx)") // rssi
.number("|(x{8})") // odometer
+ .groupBegin()
+ .number("|(xx)") // satellites
+ .groupEnd("?")
.or()
.number("|(x{9})") // odometer
.groupBegin()
@@ -118,6 +128,7 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_POSITION_LOGGED = 0x9016;
public static final int MSG_ALARM = 0x9999;
public static final int MSG_RFID = 0x9966;
+ public static final int MSG_RETRANSMISSION = 0x6688;
public static final int MSG_OBD_RT = 0x9901;
public static final int MSG_OBD_RTA = 0x9902;
@@ -242,25 +253,14 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_STATUS, parser.next());
for (int i = 1; i <= 8; i++) {
- if (parser.hasNext()) {
- position.set(Position.PREFIX_ADC + i, parser.nextHexInt(0));
- }
- }
-
- if (parser.hasNext()) {
- position.set(Position.KEY_RSSI, parser.nextHexInt(0));
+ position.set(Position.PREFIX_ADC + i, parser.nextHexInt());
}
- if (parser.hasNext()) {
- position.set(Position.KEY_ODOMETER, parser.nextLong(16, 0));
- }
- if (parser.hasNext()) {
- position.set(Position.KEY_ODOMETER, parser.nextLong(16, 0));
- }
-
- if (parser.hasNext()) {
- position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(parser.nextHexInt(0)));
- }
+ position.set(Position.KEY_RSSI, parser.nextHexInt());
+ position.set(Position.KEY_ODOMETER, parser.nextHexLong());
+ position.set(Position.KEY_SATELLITES, parser.nextHexInt());
+ position.set(Position.KEY_ODOMETER, parser.nextHexLong());
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next());
return position;
}
@@ -328,6 +328,40 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private List<Position> decodeRetransmission(ChannelBuffer buf, DeviceSession deviceSession) {
+ List<Position> positions = new LinkedList<>();
+
+ int count = buf.readUnsignedByte();
+ for (int i = 0; i < count; i++) {
+
+ buf.readUnsignedByte(); // alarm
+
+ int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\\');
+ if (endIndex < 0) {
+ endIndex = buf.writerIndex() - 4;
+ }
+
+ String sentence = buf.readBytes(endIndex - buf.readerIndex()).toString(StandardCharsets.US_ASCII);
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position = decodeRegular(position, sentence);
+
+ if (position != null) {
+ positions.add(position);
+ }
+
+ if (buf.readableBytes() > 4) {
+ buf.readUnsignedByte(); // delimiter
+ }
+
+ }
+
+ return positions;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -355,48 +389,57 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
}
}
- Position position = new Position();
- position.setProtocol(getProtocolName());
-
- if (command == MSG_ALARM) {
- short alarmCode = buf.readUnsignedByte();
- position.set(Position.KEY_ALARM, decodeAlarm(alarmCode));
- if (alarmCode >= 0x02 && alarmCode <= 0x05) {
- position.set(Position.PREFIX_IN + alarmCode, 1);
- } else if (alarmCode >= 0x32 && alarmCode <= 0x35) {
- position.set(Position.PREFIX_IN + (alarmCode - 0x30), 0);
- }
- } else if (command == MSG_POSITION_LOGGED) {
- buf.skipBytes(6);
- }
-
DeviceSession deviceSession = identify(id, channel, remoteAddress);
if (deviceSession == null) {
return null;
}
- position.setDeviceId(deviceSession.getDeviceId());
-
- if (command == MSG_RFID) {
- for (int i = 0; i < 15; i++) {
- long rfid = buf.readUnsignedInt();
- if (rfid != 0) {
- String card = String.format("%010d", rfid);
- position.set("card" + (i + 1), card);
- position.set(Position.KEY_DRIVER_UNIQUE_ID, card);
+
+ if (command == MSG_RETRANSMISSION) {
+
+ return decodeRetransmission(buf, deviceSession);
+
+ } else {
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+
+ if (command == MSG_ALARM) {
+ short alarmCode = buf.readUnsignedByte();
+ position.set(Position.KEY_ALARM, decodeAlarm(alarmCode));
+ if (alarmCode >= 0x02 && alarmCode <= 0x05) {
+ position.set(Position.PREFIX_IN + alarmCode, 1);
+ } else if (alarmCode >= 0x32 && alarmCode <= 0x35) {
+ position.set(Position.PREFIX_IN + (alarmCode - 0x30), 0);
}
+ } else if (command == MSG_POSITION_LOGGED) {
+ buf.skipBytes(6);
}
- }
- String sentence = buf.toString(buf.readerIndex(), buf.readableBytes() - 4, StandardCharsets.US_ASCII);
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ if (command == MSG_RFID) {
+ for (int i = 0; i < 15; i++) {
+ long rfid = buf.readUnsignedInt();
+ if (rfid != 0) {
+ String card = String.format("%010d", rfid);
+ position.set("card" + (i + 1), card);
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, card);
+ }
+ }
+ }
+
+ String sentence = buf.toString(buf.readerIndex(), buf.readableBytes() - 4, StandardCharsets.US_ASCII);
+
+ if (command == MSG_POSITION || command == MSG_POSITION_LOGGED || command == MSG_ALARM) {
+ return decodeRegular(position, sentence);
+ } else if (command == MSG_RFID) {
+ return decodeRfid(position, sentence);
+ } else if (command == MSG_OBD_RT) {
+ return decodeObd(position, sentence);
+ } else if (command == MSG_OBD_RTA) {
+ return decodeObdA(position, sentence);
+ }
- if (command == MSG_POSITION || command == MSG_POSITION_LOGGED || command == MSG_ALARM) {
- return decodeRegular(position, sentence);
- } else if (command == MSG_RFID) {
- return decodeRfid(position, sentence);
- } else if (command == MSG_OBD_RT) {
- return decodeObd(position, sentence);
- } else if (command == MSG_OBD_RTA) {
- return decodeObdA(position, sentence);
}
return null;
diff --git a/src/org/traccar/protocol/Pt502FrameDecoder.java b/src/org/traccar/protocol/Pt502FrameDecoder.java
index ce20dff1f..252c8dd02 100644
--- a/src/org/traccar/protocol/Pt502FrameDecoder.java
+++ b/src/org/traccar/protocol/Pt502FrameDecoder.java
@@ -37,9 +37,16 @@ public class Pt502FrameDecoder extends FrameDecoder {
}
int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\r');
- if (index != -1 && index + 1 < buf.writerIndex()) {
+ if (index < 0) {
+ index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\n');
+ }
+
+ if (index > 0) {
ChannelBuffer result = buf.readBytes(index - buf.readerIndex());
- buf.skipBytes(2);
+ while (buf.readable()
+ && (buf.getByte(buf.readerIndex()) == '\r' || buf.getByte(buf.readerIndex()) == '\n')) {
+ buf.skipBytes(1);
+ }
return result;
}
diff --git a/src/org/traccar/protocol/Pt502Protocol.java b/src/org/traccar/protocol/Pt502Protocol.java
index ad97a777e..0116422c2 100644
--- a/src/org/traccar/protocol/Pt502Protocol.java
+++ b/src/org/traccar/protocol/Pt502Protocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2016 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.
@@ -31,6 +31,7 @@ public class Pt502Protocol extends BaseProtocol {
public Pt502Protocol() {
super("pt502");
setSupportedDataCommands(
+ Command.TYPE_CUSTOM,
Command.TYPE_SET_TIMEZONE,
Command.TYPE_ALARM_SPEED,
Command.TYPE_OUTPUT_CONTROL,
diff --git a/src/org/traccar/protocol/Pt502ProtocolDecoder.java b/src/org/traccar/protocol/Pt502ProtocolDecoder.java
index fef5d9b39..1d976dcd5 100644
--- a/src/org/traccar/protocol/Pt502ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Pt502ProtocolDecoder.java
@@ -62,6 +62,10 @@ public class Pt502ProtocolDecoder extends BaseProtocolDecoder {
private String decodeAlarm(String value) {
switch (value) {
+ case "IN1":
+ return Position.ALARM_SOS;
+ case "GOF":
+ return Position.ALARM_GEOFENCE;
case "TOW":
return Position.ALARM_TOW;
case "HDA":
diff --git a/src/org/traccar/protocol/Pt502ProtocolEncoder.java b/src/org/traccar/protocol/Pt502ProtocolEncoder.java
index 4a876f6da..bd56e306a 100644
--- a/src/org/traccar/protocol/Pt502ProtocolEncoder.java
+++ b/src/org/traccar/protocol/Pt502ProtocolEncoder.java
@@ -41,6 +41,8 @@ public class Pt502ProtocolEncoder extends StringProtocolEncoder implements Strin
protected Object encodeCommand(Command command) {
switch (command.getType()) {
+ case Command.TYPE_CUSTOM:
+ return formatCommand(command, "{%s}\r\n", Command.KEY_DATA);
case Command.TYPE_OUTPUT_CONTROL:
return formatCommand(command, "#OPC{%s},{%s}\r\n", Command.KEY_INDEX, Command.KEY_DATA);
case Command.TYPE_SET_TIMEZONE:
diff --git a/src/org/traccar/protocol/RecodaProtocol.java b/src/org/traccar/protocol/RecodaProtocol.java
new file mode 100644
index 000000000..daf167fd9
--- /dev/null
+++ b/src/org/traccar/protocol/RecodaProtocol.java
@@ -0,0 +1,46 @@
+/*
+ * 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.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.nio.ByteOrder;
+import java.util.List;
+
+public class RecodaProtocol extends BaseProtocol {
+
+ public RecodaProtocol() {
+ super("recoda");
+ }
+
+ @Override
+ public void initTrackerServers(List<TrackerServer> serverList) {
+ TrackerServer server = new TrackerServer(new ServerBootstrap(), getName()) {
+ @Override
+ protected void addSpecificHandlers(ChannelPipeline pipeline) {
+ pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 4, 4, -8, 0));
+ pipeline.addLast("objectDecoder", new RecodaProtocolDecoder(RecodaProtocol.this));
+ }
+ };
+ server.setEndianness(ByteOrder.LITTLE_ENDIAN);
+ serverList.add(server);
+ }
+
+}
diff --git a/src/org/traccar/protocol/RecodaProtocolDecoder.java b/src/org/traccar/protocol/RecodaProtocolDecoder.java
new file mode 100644
index 000000000..8db582d35
--- /dev/null
+++ b/src/org/traccar/protocol/RecodaProtocolDecoder.java
@@ -0,0 +1,110 @@
+/*
+ * 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.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.helper.BitUtil;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+
+public class RecodaProtocolDecoder extends BaseProtocolDecoder {
+
+ public RecodaProtocolDecoder(RecodaProtocol protocol) {
+ super(protocol);
+ }
+
+ public static final int MSG_HEARTBEAT = 0x00001001;
+ public static final int MSG_REQUEST_RESPONSE = 0x20000001;
+ public static final int MSG_SIGNAL_LINK_REGISTRATION = 0x20001001;
+ public static final int MSG_EVENT_NOTICE = 0x20002001;
+ public static final int MSG_GPS_DATA = 0x20001011;
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ChannelBuffer buf = (ChannelBuffer) msg;
+
+ int type = buf.readInt();
+ buf.readUnsignedInt(); // length
+
+ if (type != MSG_HEARTBEAT) {
+ buf.readUnsignedShort(); // version
+ buf.readUnsignedShort(); // index
+ }
+
+ if (type == MSG_SIGNAL_LINK_REGISTRATION) {
+
+ getDeviceSession(channel, remoteAddress, buf.readBytes(12).toString(StandardCharsets.US_ASCII));
+
+ } else if (type == MSG_GPS_DATA) {
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setTime(new Date(buf.readLong()));
+
+ int flags = buf.readUnsignedByte();
+
+ if (BitUtil.check(flags, 0)) {
+
+ buf.readUnsignedShort(); // declination
+
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort()));
+
+ position.setLongitude(buf.readUnsignedByte() + buf.readUnsignedByte() / 60.0);
+ position.setLatitude(buf.readUnsignedByte() + buf.readUnsignedByte() / 60.0);
+
+ position.setLongitude(position.getLongitude() + buf.readUnsignedInt() / 3600.0);
+ position.setLatitude(position.getLatitude() + buf.readUnsignedInt() / 3600.0);
+
+ int status = buf.readUnsignedByte();
+
+ position.setValid(BitUtil.check(status, 0));
+ if (BitUtil.check(status, 1)) {
+ position.setLongitude(-position.getLongitude());
+ }
+ if (!BitUtil.check(status, 2)) {
+ position.setLatitude(-position.getLatitude());
+ }
+
+ } else {
+
+ getLastLocation(position, position.getDeviceTime());
+
+ }
+
+ return position;
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/test/org/traccar/processing/ComputedAttributesTest.java b/test/org/traccar/processing/ComputedAttributesTest.java
index ac4331c6d..fe898ff54 100644
--- a/test/org/traccar/processing/ComputedAttributesTest.java
+++ b/test/org/traccar/processing/ComputedAttributesTest.java
@@ -8,7 +8,7 @@ import org.traccar.model.Attribute;
import org.traccar.model.Position;
public class ComputedAttributesTest {
-
+
@Test
public void testComputedAttributes() {
Position position = new Position();
@@ -39,26 +39,29 @@ public class ComputedAttributesTest {
attribute.setExpression("if (event == 42) \"lowBattery\"");
Assert.assertEquals("lowBattery", computedAttributesHandler.computeAttribute(attribute, position));
-
+
attribute.setExpression("speed > 5 && valid");
Assert.assertEquals(false, computedAttributesHandler.computeAttribute(attribute, position));
-
+
attribute.setExpression("fixTime");
Assert.assertEquals(date, computedAttributesHandler.computeAttribute(attribute, position));
-
+
+ attribute.setExpression("math:pow(adc1, 2)");
+ Assert.assertEquals(16384.0, computedAttributesHandler.computeAttribute(attribute, position));
+
// modification tests
attribute.setExpression("adc1 = 256");
computedAttributesHandler.computeAttribute(attribute, position);
Assert.assertEquals(128, position.getInteger("adc1"));
-
+
attribute.setExpression("result = \"fail\"");
computedAttributesHandler.computeAttribute(attribute, position);
Assert.assertEquals("success", position.getString("result"));
-
+
attribute.setExpression("fixTime = \"2017-10-18 10:00:01\"");
computedAttributesHandler.computeAttribute(attribute, position);
Assert.assertEquals(date, position.getFixTime());
-
+
}
}
diff --git a/test/org/traccar/protocol/DwayProtocolDecoderTest.java b/test/org/traccar/protocol/DwayProtocolDecoderTest.java
index 481382535..be51f2b94 100644
--- a/test/org/traccar/protocol/DwayProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/DwayProtocolDecoderTest.java
@@ -10,13 +10,13 @@ public class DwayProtocolDecoderTest extends ProtocolTest {
DwayProtocolDecoder decoder = new DwayProtocolDecoder(new DwayProtocol());
- verifyNull(decoder, text(
+ verifyPosition(decoder, text(
"AA55,36,10024,1,171025,161055,36.0294,-79.7881,201, 2.5,111,1000,0000,00000,3578,0,0,0,D"));
- verifyNull(decoder, text(
+ verifyPosition(decoder, text(
"AA55,115,318,1,171024,195059,28.0153,-82.4761,3, 1.0,319,1000,0000,00000,4244,0,0,0,D"));
- verifyNull(decoder, text(
+ verifyPosition(decoder, text(
"AA55,117,318,1,171025,153758,28.0152,-82.4759,19, 0.6,319,1000,0000,10000,4242,0,0,0,D"));
verifyPosition(decoder, text(
diff --git a/test/org/traccar/protocol/Gt06FrameDecoderTest.java b/test/org/traccar/protocol/Gt06FrameDecoderTest.java
index ff9d4f51d..97230695a 100644
--- a/test/org/traccar/protocol/Gt06FrameDecoderTest.java
+++ b/test/org/traccar/protocol/Gt06FrameDecoderTest.java
@@ -11,35 +11,39 @@ public class Gt06FrameDecoderTest extends ProtocolTest {
Gt06FrameDecoder decoder = new Gt06FrameDecoder();
- Assert.assertEquals(
+ verifyFrame(
+ binary("787803691604130318491475905BD30E25001E10BBF7635D14759006E626560501CC0028660F213228660F1F2828660EA81E286610731428660F20140D0A"),
+ decoder.decode(null, null, binary("787803691604130318491475905BD30E25001E10BBF7635D14759006E626560501CC0028660F213228660F1F2828660EA81E286610731428660F20140D0A")));
+
+ verifyFrame(
binary("78780d0103563140414198583c0d0a"),
decoder.decode(null, null, binary("78780d0103563140414198583c0d0a")));
- Assert.assertEquals(
+ verifyFrame(
binary("787800691709261259400700cc0400d376714600d37a3d5000d37a3c5000d393505a00d3765d5a00d376735a00d32e6b640d0a"),
decoder.decode(null, null, binary("787800691709261259400700cc0400d376714600d37a3d5000d37a3c5000d393505a00d3765d5a00d376735a00d32e6b640d0a")));
- Assert.assertEquals(
+ verifyFrame(
binary("7878121011091c0b1e2e98058507f80097a6ac03344a0d0a"),
decoder.decode(null, null, binary("7878121011091c0b1e2e98058507f80097a6ac03344a0d0a")));
- Assert.assertEquals(
+ verifyFrame(
binary("787808171709281135331491827b75594dc8d719a9708452cad719a9708550cad719a97086521491827b75574cac9e17b308085dc8d71939633947cad71939633a480700cc0400d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a0d0a"),
decoder.decode(null, null, binary("787808171709281135331491827b75594dc8d719a9708452cad719a9708550cad719a97086521491827b75574cac9e17b308085dc8d71939633947cad71939633a480700cc0400d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a0d0a")));
- Assert.assertEquals(
+ verifyFrame(
binary("787808134606020002044dc5050d0a"),
decoder.decode(null, null, binary("787808134606020002044dc5050d0a")));
- Assert.assertEquals(
+ verifyFrame(
binary("78781f1210020e14061dcc0476fcd0003e3faf3e14b20000000000000000044ef6740d0a"),
decoder.decode(null, null, binary("78781f1210020e14061dcc0476fcd0003e3faf3e14b20000000000000000044ef6740d0a")));
- Assert.assertEquals(
+ verifyFrame(
binary("78780d010352887071911998000479d00d0a"),
decoder.decode(null, null, binary("78780d010352887071911998000479d00d0a")));
- Assert.assertEquals(
+ verifyFrame(
binary("78782516000000000000c000000000000000000020000900fa0210ef00fb620006640301000468030d0a"),
decoder.decode(null, null, binary("78782516000000000000c000000000000000000020000900fa0210ef00fb620006640301000468030d0a")));
diff --git a/test/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/test/org/traccar/protocol/Gt06ProtocolDecoderTest.java
index 05acd314e..ede2f385c 100644
--- a/test/org/traccar/protocol/Gt06ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/Gt06ProtocolDecoderTest.java
@@ -16,13 +16,31 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
verifyNull(decoder, binary(
"78780D01086471700328358100093F040D0A"));
+ verifyNotNull(decoder, binary(
+ "787803691604130318491475905BD30E25001E10BBF7635D14759006E626560501CC0028660F213228660F1F2828660EA81E286610731428660F20140D0A"));
+
+ verifyNotNull(decoder, binary(
+ "787800691710231108500200cc080c4e2fa5640c4e2fa66e0d0a"));
+
+ verifyNotNull(decoder, binary(
+ "787800171710231108290200cc080c4e2fa5640c4e2fa5640d0a"));
+
+ verifyNotNull(decoder, binary(
+ "787800691710231109200400cc080c4e2fa55a0c4ec0025a0c4e2fa6640c583918640d0a"));
+
+ verifyNotNull(decoder, binary(
+ "787800691710231111210700cc080c4e2fa55a0c4ec0025a0c4e39295a0c583918640c4e2fa6640c4e2fa4640c4ec854640d0a"));
+
+ verifyNotNull(decoder, binary(
+ "787800171710231112510600cc080c4e2fa55a0c4e2fa55a0c4e2fa55a0c4e2fa55a0c4e2fa55a0c4e2fa55a0d0a"));
+
verifyPosition(decoder, binary(
"7878121011091c0b1b2999058508040097a89e0034520d0a"));
- verifyNull(decoder, binary(
+ verifyNotNull(decoder, binary(
"78780869170928113413ac9e17b30808514494fcf6e148596cb0ce2c67bd4a6eb0ce2c67bd4b0018e7d4333e55ec086be7f2df5fe48d8c94fc6657e48d8cb8f378510600cc0400d37a3d4600d37a3c5000d37a3b6400d376716400d305ac6400d393506e0d0a"));
- verifyNull(decoder, binary(
+ verifyNotNull(decoder, binary(
"787808171709281135331491827b75594dc8d719a9708452cad719a9708550cad719a97086521491827b75574cac9e17b308085dc8d71939633947cad71939633a480700cc0400d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a0d0a"));
verifyNotNull(decoder, binary(
@@ -179,7 +197,7 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
verifyNull(decoder, binary(
"78780d010359339075005244340d0a"));
- verifyNull(decoder, binary(
+ verifyNotNull(decoder, binary(
"787800691709261259400700cc0400d376714600d37a3d5000d37a3c5000d393505a00d3765d5a00d376735a00d32e6b640d0a"));
verifyNull(decoder, binary(
diff --git a/test/org/traccar/protocol/MeiligaoProtocolDecoderTest.java b/test/org/traccar/protocol/MeiligaoProtocolDecoderTest.java
index 03be4807c..f5f3b3057 100644
--- a/test/org/traccar/protocol/MeiligaoProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/MeiligaoProtocolDecoderTest.java
@@ -11,6 +11,15 @@ public class MeiligaoProtocolDecoderTest extends ProtocolTest {
MeiligaoProtocolDecoder decoder = new MeiligaoProtocolDecoder(new MeiligaoProtocol());
verifyPosition(decoder, binary(
+ "2424010a142170525979ff9999753137353830322e3030302c412c313330362e303639342c4e2c31303035342e323439302c452c302e30302c3331332c3234313031372c2c2a30457c302e397c377c323530307c303030302c303030302c303130312c303241447c30323038303030353043313330313638353333427c30427c30303032313034357c30417c2520205e59454e53414241494348414924534f4e474b52414e244d522e5e5e3f3b363030373634333130303530303337333835333d3135303531393637303631343d3f2b202020202020202020202020203234202020202020202020202020312020202020202020202020203030303431313120203030313030545c0d0a"));
+
+ verifyPositions(decoder, binary(
+ "2424006661172036237118668801003039333630342e3030302c562c303330332e333231352c4e2c31303134372e313530302c452c302e30302c2c3235313031377c302e307c302e307c303030307c303030302c303030307c30303030303230343259ca0d0a"));
+
+ verifyPositions(decoder, binary(
+ "242401d961172036237118668805003039353830332e3030302c412c303330332e333431392c4e2c31303134372e343130342c452c372e30342c3230362e36312c3235313031377c302e307c302e307c303230307c303030302c303030307c3030303031313532325c003039353833332e3030302c412c303330332e323630302c4e2c31303134372e333734342c452c31302e33382c3236332e31342c3235313031377c302e307c302e307c303230307c303030302c303030307c3030303031313734355c003039353930332e3030302c412c303330332e313833382c4e2c31303134372e333735362c452c382e34392c3232332e37372c3235313031377c302e307c302e307c303230307c303030302c303030307c3030303031313839375c003039353933332e3030302c412c303330332e313033312c4e2c31303134372e333435332c452c382e37312c3139312e35302c3235313031377c302e307c302e307c303230307c303030302c303030307c3030303031323130325c003130303030302e3030302c412c303330332e313032332c4e2c31303134372e333338372c452c302e30302c3231332e36392c3235313031377c302e307c302e307c303030307c303030312c303030307c3030303031323131380d110d0a"));
+
+ verifyPosition(decoder, binary(
"2424007f1092ffffffffff9999523232303534392e3030302c412c333533372e313231372c4e2c30313130302e303633332c452c362e34382c3139332c3238303631372c2c2a30357c302e387c32347c323030307c303030432c303030417c303235443030303230303833354437427c31357c3037303636424142f7310d0a"));
verifyAttributes(decoder, binary(
diff --git a/test/org/traccar/protocol/Pt502FrameDecoderTest.java b/test/org/traccar/protocol/Pt502FrameDecoderTest.java
index 44de2459d..d654c0c61 100644
--- a/test/org/traccar/protocol/Pt502FrameDecoderTest.java
+++ b/test/org/traccar/protocol/Pt502FrameDecoderTest.java
@@ -13,19 +13,23 @@ public class Pt502FrameDecoderTest extends ProtocolTest {
Pt502FrameDecoder decoder = new Pt502FrameDecoder();
- Assert.assertEquals(
+ verifyFrame(
binary("244655533836353332383032363234333836342c3531302d56312e31322c4131312d56332e30"),
decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "bffb192d00244655533836353332383032363234333836342c3531302d56312e31322c4131312d56332e300d0d")));
- Assert.assertEquals(
+ verifyFrame(
+ binary("24504f532c313336303030303237372c3138323234312e3030302c412c303834362e303839362c4e2c30373535322e313733382c572c31332e35382c32362e38382c3239313031372c2c2c412f30303030302c30303030302f3134322c302c302c302f36323739323930302f2f6636352f2f23"),
+ decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "bffb57d50124504f532c313336303030303237372c3138323234312e3030302c412c303834362e303839362c4e2c30373535322e313733382c572c31332e35382c32362e38382c3239313031372c2c2c412f30303030302c30303030302f3134322c302c302c302f36323739323930302f2f6636352f2f230a24504f532c313336303030303237372c3138323235312e3030302c412c303834362e313234382c4e2c30373535322e313534352c572c31352e35322c33362e39332c3239313031372c2c2c412f30303030302c30303030302f3134312c302c302c302f36323739333030302f2f6636382f2f230a24504f532c313336303030303237372c3138323332342e3030302c412c303834362e323633362c4e2c30373535322e303630352c572c31382e39342c32392e39302c3239313031372c2c2c412f30303030302c30303030302f3133652c302c302c302f36323739333330302f2f6639372f2f230a24504f532c313336303030303237372c3138323332362e3030302c412c303834362e323733302c4e2c30373535322e303535342c572c31392e31322c33302e34322c3239313031372c2c2c412f30303030302c30303030302f3134302c302c302c302f36323739333330302f2f6639382f2f230a")));
+
+ verifyFrame(
binary("24504f532c3836353332383032363234333836342c3134343733352e3030302c412c313333322e373038332c4e2c3230342e363833312c452c302e302c3233302e30302c3032303531372c2c2c412f30303030302c31302f312c302f3233342f2f4646392f"),
decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "24504f532c3836353332383032363234333836342c3134343733352e3030302c412c313333322e373038332c4e2c3230342e363833312c452c302e302c3233302e30302c3032303531372c2c2c412f30303030302c31302f312c302f3233342f2f4646392f0d0a")));
- Assert.assertEquals(
+ verifyFrame(
binary("24504f532c3335333435313030303136342c3038323430352e3030302c412c313235342e383530312c4e2c31303035312e363735322c452c302e30302c3233372e39392c3136303531332c2c2c412f303030302c302f302f35353030302f2f6137312f"),
decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "24504f532c3335333435313030303136342c3038323430352e3030302c412c313235342e383530312c4e2c31303035312e363735322c452c302e30302c3233372e39392c3136303531332c2c2c412f303030302c302f302f35353030302f2f6137312f0d0a")));
- Assert.assertEquals(
+ verifyFrame(
binary("24504f532c3335333435313030303136342c3038323430352e3030302c412c313235342e383530312c4e2c31303035312e363735322c452c302e30302c3233372e39392c3136303531332c2c2c412f303030302c302f302f35353030302f2f6137312f"),
decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "bffb1b6a0024504f532c3335333435313030303136342c3038323430352e3030302c412c313235342e383530312c4e2c31303035312e363735322c452c302e30302c3233372e39392c3136303531332c2c2c412f303030302c302f302f35353030302f2f6137312f0d0a")));
diff --git a/test/org/traccar/protocol/Pt502ProtocolDecoderTest.java b/test/org/traccar/protocol/Pt502ProtocolDecoderTest.java
index 24b570937..fe66876ed 100644
--- a/test/org/traccar/protocol/Pt502ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/Pt502ProtocolDecoderTest.java
@@ -11,6 +11,9 @@ public class Pt502ProtocolDecoderTest extends ProtocolTest {
Pt502ProtocolDecoder decoder = new Pt502ProtocolDecoder(new Pt502Protocol());
verifyPosition(decoder, text(
+ "$POS,1360000277,182241.000,A,0846.0896,N,07552.1738,W,13.58,26.88,291017,,,A/00000,00000/142,0,0,0/62792900//f65//#"));
+
+ verifyPosition(decoder, text(
"$PHO0-1,1360000260,123012.000,A,0913.9644,N,07548.8345,W,0.0,309.8,111017,,,A/00000,10000/0,0,0,0/64551600//f98//"));
verifyPosition(decoder, text(
diff --git a/test/org/traccar/protocol/Pt502ProtocolEncoderTest.java b/test/org/traccar/protocol/Pt502ProtocolEncoderTest.java
index 62406d3f2..39ca2fe65 100644
--- a/test/org/traccar/protocol/Pt502ProtocolEncoderTest.java
+++ b/test/org/traccar/protocol/Pt502ProtocolEncoderTest.java
@@ -8,6 +8,20 @@ import org.traccar.model.Command;
public class Pt502ProtocolEncoderTest extends ProtocolTest {
@Test
+ public void testEncodeCustom() throws Exception {
+
+ Pt502ProtocolEncoder encoder = new Pt502ProtocolEncoder();
+
+ Command command = new Command();
+ command.setDeviceId(1);
+ command.setType(Command.TYPE_CUSTOM);
+ command.set(Command.KEY_DATA, "#PTI300");
+
+ Assert.assertEquals("#PTI300\r\n", encoder.encodeCommand(command));
+
+ }
+
+ @Test
public void testEncodeOutputControl() throws Exception {
Pt502ProtocolEncoder encoder = new Pt502ProtocolEncoder();
diff --git a/test/org/traccar/protocol/RecodaProtocolDecoderTest.java b/test/org/traccar/protocol/RecodaProtocolDecoderTest.java
new file mode 100644
index 000000000..69adb4905
--- /dev/null
+++ b/test/org/traccar/protocol/RecodaProtocolDecoderTest.java
@@ -0,0 +1,26 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+import java.nio.ByteOrder;
+
+public class RecodaProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ RecodaProtocolDecoder decoder = new RecodaProtocolDecoder(new RecodaProtocol());
+
+ verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN,
+ "01100020480000000300000030393535360000000000000001000000303030303000000000000000000000000000000000000000006100004531313037353500ffffffffffff0000"));
+
+ verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN,
+ "01200020100000000300000002000000"));
+
+ verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN,
+ "0110000008000000"));
+
+ }
+
+}