diff options
58 files changed, 1152 insertions, 306 deletions
diff --git a/setup/default.xml b/setup/default.xml index 1452137c3..f97511ed6 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -275,5 +275,8 @@ <entry key='rst.port'>5196</entry> <entry key='pt215.port'>5197</entry> <entry key='pacifictrack.port'>5198</entry> + <entry key='topin.port'>5199</entry> + <entry key='outsafe.port'>5200</entry> + <entry key='solarpowered.port'>5201</entry> </properties> diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 3acd19b6a..9adea61b0 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -191,7 +191,7 @@ public class MainModule extends AbstractModule { case "google": return new GoogleGeolocationProvider(key); case "opencellid": - return new OpenCellIdGeolocationProvider(key); + return new OpenCellIdGeolocationProvider(url, key); case "unwired": return new UnwiredGeolocationProvider(url, key); default: diff --git a/src/main/java/org/traccar/StringProtocolEncoder.java b/src/main/java/org/traccar/StringProtocolEncoder.java index d9acce7f0..e9fb65500 100644 --- a/src/main/java/org/traccar/StringProtocolEncoder.java +++ b/src/main/java/org/traccar/StringProtocolEncoder.java @@ -17,8 +17,6 @@ package org.traccar; import org.traccar.model.Command; -import java.util.Map; - public abstract class StringProtocolEncoder extends BaseProtocolEncoder { public StringProtocolEncoder(Protocol protocol) { @@ -31,21 +29,27 @@ public abstract class StringProtocolEncoder extends BaseProtocolEncoder { protected String formatCommand(Command command, String format, ValueFormatter valueFormatter, String... keys) { - String result = String.format(format, (Object[]) keys); - - result = result.replaceAll("\\{" + Command.KEY_UNIQUE_ID + "}", getUniqueId(command.getDeviceId())); - for (Map.Entry<String, Object> entry : command.getAttributes().entrySet()) { + Object[] values = new String[keys.length]; + for (int i = 0; i < keys.length; i++) { String value = null; - if (valueFormatter != null) { - value = valueFormatter.formatValue(entry.getKey(), entry.getValue()); - } - if (value == null) { - value = entry.getValue().toString(); + if (keys[i].equals(Command.KEY_UNIQUE_ID)) { + value = getUniqueId(command.getDeviceId()); + } else { + Object object = command.getAttributes().get(keys[i]); + if (valueFormatter != null) { + value = valueFormatter.formatValue(keys[i], object); + } + if (value == null && object != null) { + value = object.toString(); + } + if (value == null) { + value = ""; + } } - result = result.replaceAll("\\{" + entry.getKey() + "}", value); + values[i] = value; } - return result; + return String.format(format, values); } protected String formatCommand(Command command, String format, String... keys) { diff --git a/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java b/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java index 768aaf6a2..cb3094e16 100644 --- a/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java +++ b/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java @@ -26,11 +26,10 @@ public class OpenCellIdGeolocationProvider implements GeolocationProvider { private String url; - public OpenCellIdGeolocationProvider(String key) { - this("http://opencellid.org/cell/get", key); - } - public OpenCellIdGeolocationProvider(String url, String key) { + if (url == null) { + url = "http://opencellid.org/cell/get"; + } this.url = url + "?format=json&mcc=%d&mnc=%d&lac=%d&cellid=%d&key=" + key; } diff --git a/src/main/java/org/traccar/model/Command.java b/src/main/java/org/traccar/model/Command.java index 336fc61f4..abe538a10 100644 --- a/src/main/java/org/traccar/model/Command.java +++ b/src/main/java/org/traccar/model/Command.java @@ -68,6 +68,7 @@ public class Command extends Message implements Cloneable { public static final String KEY_UNIQUE_ID = "uniqueId"; public static final String KEY_FREQUENCY = "frequency"; + public static final String KEY_LANGUAGE = "language"; public static final String KEY_TIMEZONE = "timezone"; public static final String KEY_DEVICE_PASSWORD = "devicePassword"; public static final String KEY_RADIUS = "radius"; diff --git a/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java b/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java index 1c3dfc156..c02fa4112 100644 --- a/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java @@ -34,7 +34,7 @@ public class AdmProtocolEncoder extends StringProtocolEncoder { return formatCommand(command, "STATUS\r\n"); case Command.TYPE_CUSTOM: - return formatCommand(command, "{%s}\r\n", Command.KEY_DATA); + return formatCommand(command, "%s\r\n", Command.KEY_DATA); default: return null; diff --git a/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java b/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java index 083fe9a9e..78dbe7e91 100644 --- a/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java @@ -30,9 +30,9 @@ public class CarcellProtocolEncoder extends StringProtocolEncoder { switch (command.getType()) { case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "$SRVCMD,{%s},BA#\r\n", Command.KEY_UNIQUE_ID); + return formatCommand(command, "$SRVCMD,%s,BA#\r\n", Command.KEY_UNIQUE_ID); case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "$SRVCMD,{%s},BD#\r\n", Command.KEY_UNIQUE_ID); + return formatCommand(command, "$SRVCMD,%s,BD#\r\n", Command.KEY_UNIQUE_ID); default: return null; } diff --git a/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java b/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java index fabcae002..58a5a88e3 100644 --- a/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java @@ -213,6 +213,16 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder { } } + } else if (fieldId == 26) { + + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedIntLE()); + position.set("tripHours", buf.readUnsignedIntLE() * 1000); + + } else if (fieldId == 27) { + + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 1000); + } buf.readerIndex(fieldEnd); diff --git a/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java b/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java index 6ee305ed8..74f9e22ab 100644 --- a/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java @@ -31,13 +31,13 @@ public class EsealProtocolEncoder extends StringProtocolEncoder { switch (command.getType()) { case Command.TYPE_CUSTOM: return formatCommand( - command, "##S,eSeal,{%s},256,3.0.8,{%s},E##", Command.KEY_UNIQUE_ID, Command.KEY_DATA); + command, "##S,eSeal,%s,256,3.0.8,%s,E##", Command.KEY_UNIQUE_ID, Command.KEY_DATA); case Command.TYPE_ALARM_ARM: return formatCommand( - command, "##S,eSeal,{%s},256,3.0.8,RC-Power Control,Power OFF,E##", Command.KEY_UNIQUE_ID); + command, "##S,eSeal,%s,256,3.0.8,RC-Power Control,Power OFF,E##", Command.KEY_UNIQUE_ID); case Command.TYPE_ALARM_DISARM: return formatCommand( - command, "##S,eSeal,{%s},256,3.0.8,RC-Unlock,E##", Command.KEY_UNIQUE_ID); + command, "##S,eSeal,%s,256,3.0.8,RC-Unlock,E##", Command.KEY_UNIQUE_ID); default: return null; } diff --git a/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java index 32307446b..dd0672c23 100644 --- a/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java @@ -32,17 +32,17 @@ public class Gl200ProtocolEncoder extends StringProtocolEncoder { switch (command.getType()) { case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "AT+GTRTO={%s},1,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "AT+GTRTO=%s,1,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "AT+GTOUT={%s},1,,,0,0,0,0,0,0,0,,,,,,,FFFF$", + return formatCommand(command, "AT+GTOUT=%s,1,,,0,0,0,0,0,0,0,,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "AT+GTOUT={%s},0,,,0,0,0,0,0,0,0,,,,,,,FFFF$", + return formatCommand(command, "AT+GTOUT=%s,0,,,0,0,0,0,0,0,0,,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); case Command.TYPE_IDENTIFICATION: - return formatCommand(command, "AT+GTRTO={%s},8,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "AT+GTRTO=%s,8,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); case Command.TYPE_REBOOT_DEVICE: - return formatCommand(command, "AT+GTRTO={%s},3,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "AT+GTRTO=%s,3,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); default: return null; } diff --git a/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java index 7128823ed..e662e9b04 100644 --- a/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java @@ -47,24 +47,24 @@ public class Gps103ProtocolEncoder extends StringProtocolEncoder implements Stri switch (command.getType()) { case Command.TYPE_CUSTOM: - return formatCommand(command, "**,imei:{%s},{%s}", Command.KEY_UNIQUE_ID, Command.KEY_DATA); + return formatCommand(command, "**,imei:%s,%s", Command.KEY_UNIQUE_ID, Command.KEY_DATA); case Command.TYPE_POSITION_STOP: - return formatCommand(command, "**,imei:{%s},A", Command.KEY_UNIQUE_ID); + return formatCommand(command, "**,imei:%s,A", Command.KEY_UNIQUE_ID); case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "**,imei:{%s},B", Command.KEY_UNIQUE_ID); + return formatCommand(command, "**,imei:%s,B", Command.KEY_UNIQUE_ID); case Command.TYPE_POSITION_PERIODIC: return formatCommand( - command, "**,imei:{%s},C,{%s}", this, Command.KEY_UNIQUE_ID, Command.KEY_FREQUENCY); + command, "**,imei:%s,C,%s", this, Command.KEY_UNIQUE_ID, Command.KEY_FREQUENCY); case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "**,imei:{%s},J", Command.KEY_UNIQUE_ID); + return formatCommand(command, "**,imei:%s,J", Command.KEY_UNIQUE_ID); case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "**,imei:{%s},K", Command.KEY_UNIQUE_ID); + return formatCommand(command, "**,imei:%s,K", Command.KEY_UNIQUE_ID); case Command.TYPE_ALARM_ARM: - return formatCommand(command, "**,imei:{%s},L", Command.KEY_UNIQUE_ID); + return formatCommand(command, "**,imei:%s,L", Command.KEY_UNIQUE_ID); case Command.TYPE_ALARM_DISARM: - return formatCommand(command, "**,imei:{%s},M", Command.KEY_UNIQUE_ID); + return formatCommand(command, "**,imei:%s,M", Command.KEY_UNIQUE_ID); case Command.TYPE_REQUEST_PHOTO: - return formatCommand(command, "**,imei:{%s},160", Command.KEY_UNIQUE_ID); + return formatCommand(command, "**,imei:%s,160", Command.KEY_UNIQUE_ID); default: return null; } diff --git a/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java b/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java index 7dd4b2d77..be0ab5130 100644 --- a/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java +++ b/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java @@ -32,7 +32,7 @@ public class GranitProtocolSmsEncoder extends StringProtocolEncoder { case Command.TYPE_REBOOT_DEVICE: return "BB+RESET"; case Command.TYPE_POSITION_PERIODIC: - return formatCommand(command, "BB+BBMD={%s}", Command.KEY_FREQUENCY); + return formatCommand(command, "BB+BBMD=%s", Command.KEY_FREQUENCY); default: return null; } diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index e1ff0b6b6..b51da00d7 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -209,7 +209,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { sendResponse(channel, false, MSG_X1_PHOTO_DATA, 0, content); } - private boolean decodeGps(Position position, ByteBuf buf, boolean hasLength, TimeZone timezone) { + public static boolean decodeGps(Position position, ByteBuf buf, boolean hasLength, TimeZone timezone) { DateBuilder dateBuilder = new DateBuilder(timezone) .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) @@ -548,6 +548,15 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); + long portInfo = buf.readUnsignedInt(); + + position.set(Position.KEY_INPUT, buf.readUnsignedByte()); + position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); + + for (int i = 1; i <= BitUtil.between(portInfo, 20, 24); i++) { + position.set(Position.PREFIX_ADC + i, buf.readUnsignedShort() * 0.01); + } + return position; } else if (type == MSG_X1_PHOTO_INFO) { @@ -1011,7 +1020,28 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { while (buf.readableBytes() > 6) { int moduleType = buf.readUnsignedShort(); int moduleLength = buf.readUnsignedShort(); + switch (moduleType) { + case 0x03: + position.set(Position.KEY_ICCID, ByteBufUtil.hexDump(buf.readSlice(10))); + break; + case 0x09: + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + break; + case 0x0a: + position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedByte()); + break; + case 0x11: + CellTower cellTower = CellTower.from( + buf.readUnsignedShort(), + buf.readUnsignedShort(), + buf.readUnsignedShort(), + buf.readUnsignedMedium(), + buf.readUnsignedByte()); + if (cellTower.getCellId() > 0) { + position.setNetwork(new Network(cellTower)); + } + break; case 0x18: position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); break; @@ -1072,6 +1102,11 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { position.setLatitude(latitude); position.setLongitude(longitude); break; + case 0x34: + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + buf.readUnsignedIntLE(); // time + buf.skipBytes(buf.readUnsignedByte()); // content + break; default: buf.skipBytes(moduleLength); break; diff --git a/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java index 137689a67..47e5aede0 100644 --- a/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java @@ -185,7 +185,7 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder { .number("(d+)(dd.d+),") // longitude .groupEnd() .expression("([EW]),") - .number("(d+.?d*),") // speed + .number(" *(d+.?d*),") // speed .number("(d+.?d*)?,") // course .number("(?:d+,)?") // battery .number("(?:(dd)(dd)(dd))?") // date (ddmmyy) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index fceefa73a..342edb22b 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -98,6 +98,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(value, 20)) { return Position.ALARM_GEOFENCE; } + if (BitUtil.check(value, 28)) { + return Position.ALARM_MOVEMENT; + } if (BitUtil.check(value, 29)) { return Position.ALARM_ACCIDENT; } @@ -160,22 +163,23 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedInt())); - int flags = buf.readInt(); + int status = buf.readInt(); - position.set(Position.KEY_IGNITION, BitUtil.check(flags, 0)); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 0)); + position.set(Position.KEY_BLOCKED, BitUtil.check(status, 10)); - position.setValid(BitUtil.check(flags, 1)); + position.setValid(BitUtil.check(status, 1)); double lat = buf.readUnsignedInt() * 0.000001; double lon = buf.readUnsignedInt() * 0.000001; - if (BitUtil.check(flags, 2)) { + if (BitUtil.check(status, 2)) { position.setLatitude(-lat); } else { position.setLatitude(lat); } - if (BitUtil.check(flags, 3)) { + if (BitUtil.check(status, 3)) { position.setLongitude(-lon); } else { position.setLongitude(lon); @@ -211,6 +215,13 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x31: position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); break; + case 0x33: + String sentence = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + if (sentence.startsWith("*M00")) { + String lockStatus = sentence.substring(8, 8 + 7); + position.set(Position.KEY_BATTERY, Integer.parseInt(lockStatus.substring(2, 5)) * 0.01); + } + break; case 0x91: position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.1); position.set(Position.KEY_RPM, buf.readUnsignedShort()); @@ -231,7 +242,17 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); } break; + case 0xD0: + long userStatus = buf.readUnsignedInt(); + if (BitUtil.check(userStatus, 3)) { + position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); + } + break; + case 0xD3: + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1); + break; default: + System.out.print(String.format("%02x ", subtype)); break; } buf.readerIndex(endIndex); @@ -257,4 +278,3 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } } - diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java index 343ac9431..0c9f8ebb8 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java @@ -40,13 +40,13 @@ public class LaipacProtocolEncoder extends StringProtocolEncoder { switch (command.getType()) { case Command.TYPE_CUSTOM: - return formatCommand(command, "{%s}", + return formatCommand(command, "%s", Command.KEY_DATA); case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "AVREQ,{%s},1", + return formatCommand(command, "AVREQ,%s,1", Command.KEY_DEVICE_PASSWORD); case Command.TYPE_REBOOT_DEVICE: - return formatCommand(command, "AVRESET,{%s},{%s}", + return formatCommand(command, "AVRESET,%s,%s", Command.KEY_UNIQUE_ID, Command.KEY_DEVICE_PASSWORD); default: return null; diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java b/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java index 36fb9fc2f..059f688f7 100644 --- a/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java @@ -57,28 +57,28 @@ public class MiniFinderProtocolEncoder extends StringProtocolEncoder implements switch (command.getType()) { case Command.TYPE_SET_TIMEZONE: - return formatCommand(command, "{%s}L{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_TIMEZONE); + return formatCommand(command, "%sL%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_TIMEZONE); case Command.TYPE_VOICE_MONITORING: - return formatCommand(command, "{%s}P{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); + return formatCommand(command, "%sP%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); case Command.TYPE_ALARM_SPEED: - return formatCommand(command, "{%s}J1{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA); + return formatCommand(command, "%sJ1%s", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA); case Command.TYPE_ALARM_GEOFENCE: - return formatCommand(command, "{%s}R1{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_RADIUS); + return formatCommand(command, "%sR1%s", Command.KEY_DEVICE_PASSWORD, Command.KEY_RADIUS); case Command.TYPE_ALARM_VIBRATION: - return formatCommand(command, "{%s}W1,{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA); + return formatCommand(command, "%sW1,%s", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA); case Command.TYPE_SET_AGPS: - return formatCommand(command, "{%s}AGPS{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); + return formatCommand(command, "%sAGPS%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); case Command.TYPE_ALARM_FALL: - return formatCommand(command, "{%s}F{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); + return formatCommand(command, "%sF%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); case Command.TYPE_MODE_POWER_SAVING: - return formatCommand(command, "{%s}SP{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); + return formatCommand(command, "%sSP%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); case Command.TYPE_MODE_DEEP_SLEEP: - return formatCommand(command, "{%s}DS{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); + return formatCommand(command, "%sDS%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); case Command.TYPE_SOS_NUMBER: - return formatCommand(command, "{%s}{%s}1,{%s}", this, + return formatCommand(command, "%s%s1,%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_INDEX, Command.KEY_PHONE); case Command.TYPE_SET_INDICATOR: - return formatCommand(command, "{%s}LED{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA); + return formatCommand(command, "%sLED%s", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA); default: return null; } diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index 75c8b11d3..b6f257d2c 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -117,6 +117,10 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { case 0x02: position.set(Position.KEY_ALARM, decodeAlarm(buf.readIntLE())); break; + case 0x14: + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); + break; case 0x20: position.setLatitude(buf.readIntLE() * 0.0000001); position.setLongitude(buf.readIntLE() * 0.0000001); @@ -152,7 +156,9 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { break; case 0x24: position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); - position.set(Position.KEY_STATUS, buf.readUnsignedIntLE()); + long status = buf.readUnsignedIntLE(); + position.set(Position.KEY_BATTERY_LEVEL, BitUtil.from(status, 24)); + position.set(Position.KEY_STATUS, status); break; case 0x40: buf.readUnsignedIntLE(); // timestamp diff --git a/src/main/java/org/traccar/protocol/OutsafeProtocol.java b/src/main/java/org/traccar/protocol/OutsafeProtocol.java new file mode 100644 index 000000000..c728a404d --- /dev/null +++ b/src/main/java/org/traccar/protocol/OutsafeProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class OutsafeProtocol extends BaseProtocol { + + public OutsafeProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(65535)); + pipeline.addLast(new OutsafeProtocolDecoder(OutsafeProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java b/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java new file mode 100644 index 000000000..5e95270e8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java @@ -0,0 +1,69 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.model.Position; + +import javax.json.Json; +import javax.json.JsonObject; +import java.io.StringReader; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +public class OutsafeProtocolDecoder extends BaseHttpProtocolDecoder { + + public OutsafeProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + String content = request.content().toString(StandardCharsets.UTF_8); + JsonObject json = Json.createReader(new StringReader(content)).readObject(); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, json.getString("device")); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date()); + position.setValid(true); + position.setLatitude(json.getJsonNumber("latitude").doubleValue()); + position.setLongitude(json.getJsonNumber("longitude").doubleValue()); + position.setAltitude(json.getJsonNumber("altitude").doubleValue()); + position.setCourse(json.getJsonNumber("heading").intValue()); + + position.set(Position.KEY_RSSI, json.getJsonNumber("rssi").intValue()); + + sendResponse(channel, HttpResponseStatus.OK); + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java b/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java index 106889ee0..949c994ee 100644 --- a/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java @@ -19,6 +19,7 @@ import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.DeviceSession; import org.traccar.Protocol; +import org.traccar.helper.BitUtil; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; import org.traccar.helper.UnitsConverter; @@ -40,17 +41,30 @@ public class PluginProtocolDecoder extends BaseProtocolDecoder { .number("(dd)(dd)(dd),") // time (hhmmss) .number("(-?d+.d+),") // longitude .number("(-?d+.d+),") // latitude - .number("(d+),") // speed + .number("(d+.?d*),") // speed .number("(d+),") // course .number("(-?d+),") // altitude .number("(-?d+),") // satellites .number("d+,") // type - .number("(d+),") // odometer + .number("(d+.?d*),") // odometer .number("(d+),") // status - .expression("[^,]*,") + .number("(d+.?d*),") // fuel .expression("[^,]*,") .text("0") .groupBegin() + .number(",(-?d+.?d*)") // temperature 1 + .number(",(-?d+.?d*)") // temperature 2 + .number(",d+") // oil level + .number(",(d+)") // rpm + .number(",(d+)") // obd speed + .number(",d+") // people up + .number(",d+") // people down + .number(",d+") // obd status + .number(",d+") // fuel intake air temperature + .number(",(d+)") // throttle + .number(",(d+)") // battery + .groupEnd("?") + .groupBegin() .text(",+,") .number("(d+),") // event .groupEnd("?") @@ -74,18 +88,50 @@ public class PluginProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - position.setValid(true); position.setTime(parser.nextDateTime()); position.setLongitude(parser.nextDouble()); position.setLatitude(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); position.setCourse(parser.nextInt()); position.setAltitude(parser.nextInt()); position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_ODOMETER, parser.nextInt()); - position.set(Position.KEY_STATUS, parser.nextInt()); - position.set(Position.KEY_EVENT, parser.nextInt()); + position.set(Position.KEY_ODOMETER, (long) (parser.nextDouble() * 1000)); + + int status = parser.nextInt(); + position.setValid(BitUtil.check(status, 0)); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 1)); + for (int i = 0; i < 4; i++) { + position.set(Position.PREFIX_IN + (i + 1), BitUtil.check(status, 20 + i)); + } + position.set(Position.KEY_STATUS, status); + + position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble()); + + if (parser.hasNext(6)) { + position.set(Position.PREFIX_TEMP + 1, parser.nextDouble()); + position.set(Position.PREFIX_TEMP + 2, parser.nextDouble()); + position.set(Position.KEY_RPM, parser.nextInt()); + position.set(Position.KEY_OBD_SPEED, parser.nextInt()); + position.set(Position.KEY_THROTTLE, parser.nextInt() * 0.1); + position.set(Position.KEY_POWER, parser.nextInt() * 0.1); + } + + if (parser.hasNext()) { + int event = parser.nextInt(); + switch (event) { + case 11317: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 11319: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + default: + break; + + } + position.set(Position.KEY_EVENT, event); + } return position; } diff --git a/src/main/java/org/traccar/protocol/Pt215FrameDecoder.java b/src/main/java/org/traccar/protocol/Pt215FrameDecoder.java deleted file mode 100644 index 0b3bae914..000000000 --- a/src/main/java/org/traccar/protocol/Pt215FrameDecoder.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2019 Anton Tananaev (anton@traccar.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.traccar.protocol; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class Pt215FrameDecoder extends BaseFrameDecoder { - - private ByteBuf decodeFrame(ByteBuf buf, int length) { - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - return null; - } - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 5) { - return null; - } - - int type = buf.getUnsignedByte(buf.readerIndex() + 2 + 1); - switch (type) { - case Pt215ProtocolDecoder.MSG_LOGIN: - return decodeFrame(buf, 15); - case Pt215ProtocolDecoder.MSG_GPS_REALTIME: - case Pt215ProtocolDecoder.MSG_GPS_OFFLINE: - return decodeFrame(buf, 27); - case Pt215ProtocolDecoder.MSG_STATUS: - return decodeFrame(buf, 11); - default: - return null; - - } - } - -} diff --git a/src/main/java/org/traccar/protocol/Pt215Protocol.java b/src/main/java/org/traccar/protocol/Pt215Protocol.java index 31ddc2c7a..09bd9b121 100644 --- a/src/main/java/org/traccar/protocol/Pt215Protocol.java +++ b/src/main/java/org/traccar/protocol/Pt215Protocol.java @@ -15,6 +15,7 @@ */ package org.traccar.protocol; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; @@ -25,7 +26,7 @@ public class Pt215Protocol extends BaseProtocol { addServer(new TrackerServer(false, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new Pt215FrameDecoder()); + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 1, -1, 0)); pipeline.addLast(new Pt215ProtocolDecoder(Pt215Protocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java index ba08b16ae..364ecae86 100644 --- a/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java @@ -46,13 +46,13 @@ public class Pt502ProtocolEncoder extends StringProtocolEncoder implements Strin switch (command.getType()) { case Command.TYPE_CUSTOM: - return formatCommand(command, "{%s}\r\n", Command.KEY_DATA); + 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); + return formatCommand(command, "#OPC%s,%s\r\n", Command.KEY_INDEX, Command.KEY_DATA); case Command.TYPE_SET_TIMEZONE: - return formatCommand(command, "#TMZ{%s}\r\n", Command.KEY_TIMEZONE); + return formatCommand(command, "#TMZ%s\r\n", Command.KEY_TIMEZONE); case Command.TYPE_ALARM_SPEED: - return formatCommand(command, "#SPD{%s}\r\n", Command.KEY_DATA); + return formatCommand(command, "#SPD%s\r\n", Command.KEY_DATA); case Command.TYPE_REQUEST_PHOTO: return formatCommand(command, "#PHO\r\n"); default: diff --git a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java index 071200d6d..f9c8d9df8 100644 --- a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java @@ -20,6 +20,7 @@ import org.traccar.BaseProtocolDecoder; import org.traccar.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; +import org.traccar.helper.BitUtil; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; import org.traccar.helper.UnitsConverter; @@ -84,10 +85,10 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { String firmware = parser.next(); String serial = parser.next(); int index = parser.nextInt(); - int type = parser.nextInt(); + parser.nextInt(); // type if (channel != null && archive.equals("A")) { - String response = "RST;A;" + model + ";" + firmware + ";" + serial + ";" + index + ";" + type + ";FIM;"; + String response = "RST;A;" + model + ";" + firmware + ";" + serial + ";" + index + ";6;FIM;"; channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } @@ -120,7 +121,10 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ODOMETER, parser.nextInt()); position.set(Position.KEY_RSSI, parser.nextInt()); position.set(Position.PREFIX_TEMP + 1, (int) parser.nextHexInt().byteValue()); - position.set(Position.KEY_STATUS, parser.nextHexInt() << 8 + parser.nextHexInt()); + + int status = parser.nextHexInt() << 8 + parser.nextHexInt(); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 7)); + position.set(Position.KEY_STATUS, status); return position; } diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java index f9c79fb5b..304f61836 100644 --- a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java @@ -24,6 +24,7 @@ import io.netty.handler.codec.http.HttpResponseStatus; import org.traccar.BaseHttpProtocolDecoder; import org.traccar.DeviceSession; import org.traccar.Protocol; +import org.traccar.helper.BitUtil; import org.traccar.helper.DataConverter; import org.traccar.helper.UnitsConverter; import org.traccar.model.Network; @@ -31,7 +32,10 @@ import org.traccar.model.Position; import org.traccar.model.WifiAccessPoint; import javax.json.Json; +import javax.json.JsonNumber; import javax.json.JsonObject; +import javax.json.JsonString; +import javax.json.JsonValue; import java.io.StringReader; import java.net.SocketAddress; import java.net.URLDecoder; @@ -44,6 +48,30 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { super(protocol); } + private int getJsonInt(JsonObject json, String key) { + JsonValue value = json.get(key); + if (value != null) { + if (value.getValueType() == JsonValue.ValueType.NUMBER) { + return ((JsonNumber) value).intValue(); + } else if (value.getValueType() == JsonValue.ValueType.STRING) { + return Integer.parseInt(((JsonString) value).getString()); + } + } + return 0; + } + + private double getJsonDouble(JsonObject json, String key) { + JsonValue value = json.get(key); + if (value != null) { + if (value.getValueType() == JsonValue.ValueType.NUMBER) { + return ((JsonNumber) value).doubleValue(); + } else if (value.getValueType() == JsonValue.ValueType.STRING) { + return Double.parseDouble(((JsonString) value).getString()); + } + } + return 0; + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -65,18 +93,24 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { position.setDeviceId(deviceSession.getDeviceId()); if (json.containsKey("time")) { - position.setTime(new Date(json.getInt("time") * 1000L)); + position.setTime(new Date(getJsonInt(json, "time") * 1000L)); } else { position.setTime(new Date()); } - if (json.containsKey("location")) { + if (json.containsKey("location") + || json.containsKey("lat") && json.containsKey("lng") && !json.containsKey("data")) { - JsonObject location = json.getJsonObject("location"); + JsonObject location; + if (json.containsKey("location")) { + location = json.getJsonObject("location"); + } else { + location = json; + } position.setValid(true); - position.setLatitude(location.getJsonNumber("lat").doubleValue()); - position.setLongitude(location.getJsonNumber("lng").doubleValue()); + position.setLatitude(getJsonDouble(location, "lat")); + position.setLongitude(getJsonDouble(location, "lng")); } else { @@ -84,7 +118,25 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(data)); try { int event = buf.readUnsignedByte(); - if (event >> 4 == 0) { + if (event == 0x0f || event == 0x1f) { + + position.setValid(event >> 4 > 0); + + long value; + value = buf.readUnsignedInt(); + position.setLatitude(BitUtil.to(value, 31) * 0.000001); + if (BitUtil.check(value, 31)) { + position.setLatitude(-position.getLatitude()); + } + value = buf.readUnsignedInt(); + position.setLongitude(BitUtil.to(value, 31) * 0.000001); + if (BitUtil.check(value, 31)) { + position.setLongitude(-position.getLongitude()); + } + + position.set(Position.KEY_BATTERY, (int) buf.readUnsignedByte()); + + } else if (event >> 4 == 0) { position.setValid(true); position.setLatitude(buf.readIntLE() * 0.0000001); @@ -154,10 +206,10 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { } if (json.containsKey("rssi")) { - position.set(Position.KEY_RSSI, json.getJsonNumber("rssi").doubleValue()); + position.set(Position.KEY_RSSI, getJsonDouble(json, "rssi")); } if (json.containsKey("seqNumber")) { - position.set(Position.KEY_INDEX, json.getInt("seqNumber")); + position.set(Position.KEY_INDEX, getJsonInt(json, "seqNumber")); } sendResponse(channel, HttpResponseStatus.OK); diff --git a/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java b/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java new file mode 100644 index 000000000..53a948cdc --- /dev/null +++ b/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java @@ -0,0 +1,34 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class SolarPoweredProtocol extends BaseProtocol { + + public SolarPoweredProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HuabaoFrameDecoder()); + pipeline.addLast(new SolarPoweredProtocolDecoder(SolarPoweredProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java b/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java new file mode 100644 index 000000000..eae37386a --- /dev/null +++ b/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java @@ -0,0 +1,97 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; + +public class SolarPoweredProtocolDecoder extends BaseProtocolDecoder { + + public SolarPoweredProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_ACTIVE_REPORTING = 0x11; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // start marker + + String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(0, 15); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + int type = buf.readUnsignedByte(); + buf.readUnsignedShort(); // attributes + + if (type == MSG_ACTIVE_REPORTING) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + while (buf.readableBytes() > 2) { + int tag = buf.readUnsignedByte(); + int length = buf.readUnsignedByte(); + switch (tag) { + case 0x81: + int status = buf.readUnsignedByte(); + DateBuilder dateBuilder = new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + position.setLatitude(buf.readUnsignedInt() * 0.000001); + if (BitUtil.check(status, 3)) { + position.setLatitude(-position.getLatitude()); + } + position.setLongitude(buf.readUnsignedInt() * 0.000001); + if (BitUtil.check(status, 2)) { + position.setLongitude(-position.getLongitude()); + } + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.set(Position.KEY_DEVICE_TEMP, (int) buf.readByte()); + position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.02); + position.setCourse(buf.readUnsignedByte()); + break; + default: + buf.skipBytes(length); + break; + } + } + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java index 90151d061..5ffddb318 100644 --- a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java @@ -18,6 +18,7 @@ package org.traccar.protocol; import io.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; @@ -66,7 +67,7 @@ public class StarcomProtocolDecoder extends BaseProtocolDecoder { position.setAltitude(Double.parseDouble(value)); break; case "velocity": - position.setSpeed(Integer.parseInt(value)); + position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(value))); break; case "heading": position.setCourse(Integer.parseInt(value)); @@ -74,8 +75,8 @@ public class StarcomProtocolDecoder extends BaseProtocolDecoder { case "eventid": position.set(Position.KEY_EVENT, Integer.parseInt(value)); break; - case "odometer": - position.set(Position.KEY_ODOMETER, Long.parseLong(value)); + case "mileage": + position.set(Position.KEY_ODOMETER, (long) (Double.parseDouble(value) * 1000)); break; case "satellites": position.set(Position.KEY_SATELLITES, Integer.parseInt(value)); diff --git a/src/main/java/org/traccar/protocol/SuntechFrameDecoder.java b/src/main/java/org/traccar/protocol/SuntechFrameDecoder.java index de8de17f0..7b8337468 100644 --- a/src/main/java/org/traccar/protocol/SuntechFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/SuntechFrameDecoder.java @@ -32,13 +32,24 @@ public class SuntechFrameDecoder extends BaseFrameDecoder { protected Object decode( ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - int delimiterIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\r'); - while (delimiterIndex > 0) { - if (delimiterIndex + 1 < buf.writerIndex() && buf.getByte(delimiterIndex + 1) == '\n') { - delimiterIndex = buf.indexOf(delimiterIndex + 1, buf.writerIndex(), (byte) '\r'); - } else { - return readFrame(buf, delimiterIndex); + if (buf.getByte(buf.readerIndex()) == (byte) 0x81) { + + int length = 1 + 2 + buf.getShort(buf.readerIndex() + 1); + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); } + + } else { + + int delimiterIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\r'); + while (delimiterIndex > 0) { + if (delimiterIndex + 1 < buf.writerIndex() && buf.getByte(delimiterIndex + 1) == '\n') { + delimiterIndex = buf.indexOf(delimiterIndex + 1, buf.writerIndex(), (byte) '\r'); + } else { + return readFrame(buf, delimiterIndex); + } + } + } return null; diff --git a/src/main/java/org/traccar/protocol/SuntechProtocol.java b/src/main/java/org/traccar/protocol/SuntechProtocol.java index 7e2c20e6f..199885537 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocol.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocol.java @@ -15,7 +15,6 @@ */ package org.traccar.protocol; -import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; @@ -38,7 +37,6 @@ public class SuntechProtocol extends BaseProtocol { protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new SuntechFrameDecoder()); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); pipeline.addLast(new SuntechProtocolEncoder(SuntechProtocol.this)); pipeline.addLast(new SuntechProtocolDecoder(SuntechProtocol.this)); } diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java index e40096a77..601d127f1 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java @@ -15,18 +15,22 @@ */ package org.traccar.protocol; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.Context; import org.traccar.DeviceSession; import org.traccar.Protocol; import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; import org.traccar.helper.UnitsConverter; import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -34,6 +38,8 @@ import java.util.TimeZone; public class SuntechProtocolDecoder extends BaseProtocolDecoder { + private String prefix; + private int protocolType; private boolean hbm; private boolean includeAdc; @@ -44,6 +50,10 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { super(protocol); } + public String getPrefix() { + return prefix; + } + public void setProtocolType(int protocolType) { this.protocolType = protocolType; } @@ -268,7 +278,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { position.setDeviceId(deviceSession.getDeviceId()); position.set(Position.KEY_TYPE, type); - if (protocol.equals("ST300") || protocol.equals("ST500") || protocol.equals("ST600")) { + if (protocol.startsWith("ST3") || protocol.equals("ST500") || protocol.equals("ST600")) { index += 1; // model } @@ -300,7 +310,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_POWER, Double.parseDouble(values[index++])); String io = values[index++]; - if (io.length() == 6) { + if (io.length() >= 6) { position.set(Position.KEY_IGNITION, io.charAt(0) == '1'); position.set(Position.PREFIX_IN + 1, io.charAt(1) == '1'); position.set(Position.PREFIX_IN + 2, io.charAt(2) == '1'); @@ -501,20 +511,138 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { return position; } + private Position decodeBinary( + Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + int type = buf.readUnsignedByte(); + buf.readUnsignedShort(); // length + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, ByteBufUtil.hexDump(buf.readSlice(5))); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + int mask = buf.readUnsignedMedium(); + + if (BitUtil.check(mask, 1)) { + buf.readUnsignedByte(); // model + } + + if (BitUtil.check(mask, 2)) { + position.set(Position.KEY_VERSION_FW, String.format("%d.%d.%d", + buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())); + } + + if (BitUtil.check(mask, 3) && buf.readUnsignedByte() == 0) { + position.set(Position.KEY_ARCHIVE, true); + } + + if (BitUtil.check(mask, 4) && BitUtil.check(mask, 5)) { + position.setTime(new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .getDate()); + } + + if (BitUtil.check(mask, 6)) { + buf.readUnsignedInt(); // cell + } + + if (BitUtil.check(mask, 7)) { + buf.readUnsignedShort(); // mcc + } + + if (BitUtil.check(mask, 8)) { + buf.readUnsignedShort(); // mnc + } + + if (BitUtil.check(mask, 9)) { + buf.readUnsignedShort(); // lac + } + + if (BitUtil.check(mask, 10)) { + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + } + + if (BitUtil.check(mask, 11)) { + long value = buf.readUnsignedInt(); + if (BitUtil.check(value, 31)) { + value = -BitUtil.to(value, 31); + } + position.setLatitude(value / 1000000.0); + } + + if (BitUtil.check(mask, 12)) { + long value = buf.readUnsignedInt(); + if (BitUtil.check(value, 31)) { + value = -BitUtil.to(value, 31); + } + position.setLongitude(value / 1000000.0); + } + + if (BitUtil.check(mask, 13)) { + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort() / 100.0)); + } + + if (BitUtil.check(mask, 14)) { + position.setCourse(buf.readUnsignedShort() / 100.0); + } + + if (BitUtil.check(mask, 15)) { + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + } + + if (BitUtil.check(mask, 16)) { + position.setValid(buf.readUnsignedByte() > 0); + } + + if (BitUtil.check(mask, 17)) { + int input = buf.readUnsignedByte(); + position.set(Position.KEY_IGNITION, BitUtil.check(input, 0)); + position.set(Position.KEY_INPUT, input); + } + + if (BitUtil.check(mask, 18)) { + position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); + } + + if (BitUtil.check(mask, 19)) { + int value = buf.readUnsignedByte(); + if (type == 0x82) { + position.set(Position.KEY_ALARM, decodeAlert(value)); + } + } + + return position; + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - String[] values = ((String) msg).split(";"); + ByteBuf buf = (ByteBuf) msg; + + if (buf.getByte(buf.readerIndex()) == (byte) 0x81) { + + return decodeBinary(channel, remoteAddress, buf); - if (values[0].length() < 5) { - return decodeUniversal(channel, remoteAddress, values); - } else if (values[0].startsWith("ST9")) { - return decode9(channel, remoteAddress, values); - } else if (values[0].startsWith("ST4")) { - return decode4(channel, remoteAddress, values); } else { - return decode2356(channel, remoteAddress, values[0].substring(0, 5), values); + + String[] values = buf.toString(StandardCharsets.US_ASCII).split(";"); + prefix = values[0]; + + if (prefix.length() < 5) { + return decodeUniversal(channel, remoteAddress, values); + } else if (prefix.startsWith("ST9")) { + return decode9(channel, remoteAddress, values); + } else if (prefix.startsWith("ST4")) { + return decode4(channel, remoteAddress, values); + } else { + return decode2356(channel, remoteAddress, prefix.substring(0, 5), values); + } } } diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java index 6dae42ad5..3b4995110 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java @@ -15,6 +15,8 @@ */ package org.traccar.protocol; +import io.netty.channel.Channel; +import org.traccar.BasePipelineFactory; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; import org.traccar.Protocol; @@ -25,32 +27,49 @@ public class SuntechProtocolEncoder extends StringProtocolEncoder { super(protocol); } + private String getPrefix(Channel channel) { + String prefix = "SA200CMD"; + if (channel != null) { + SuntechProtocolDecoder protocolDecoder = + BasePipelineFactory.getHandler(channel.pipeline(), SuntechProtocolDecoder.class); + if (protocolDecoder != null) { + String decoderPrefix = protocolDecoder.getPrefix(); + if (decoderPrefix != null && decoderPrefix.length() > 5) { + prefix = decoderPrefix.substring(0, decoderPrefix.length() - 3) + "CMD"; + } + } + } + return prefix; + } + @Override - protected Object encodeCommand(Command command) { + protected Object encodeCommand(Channel channel, Command command) { + + String prefix = getPrefix(channel); switch (command.getType()) { case Command.TYPE_REBOOT_DEVICE: - return formatCommand(command, "SA200CMD;{%s};02;Reboot\r", Command.KEY_UNIQUE_ID); + return formatCommand(command, prefix + ";%s;02;Reboot\r", Command.KEY_UNIQUE_ID); case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "SA200GTR;{%s};02;\r", Command.KEY_UNIQUE_ID); + return formatCommand(command, prefix + ";%s;02;\r", Command.KEY_UNIQUE_ID); case Command.TYPE_OUTPUT_CONTROL: if (command.getAttributes().containsKey(Command.KEY_DATA)) { if (command.getAttributes().get(Command.KEY_DATA).equals("1")) { - return formatCommand(command, "SA200CMD;{%s};02;Enable{%s}\r", + return formatCommand(command, prefix + ";%s;02;Enable%s\r", Command.KEY_UNIQUE_ID, Command.KEY_INDEX); } else { - return formatCommand(command, "SA200CMD;{%s};02;Disable{%s}\r", + return formatCommand(command, prefix + ";%s;02;Disable%s\r", Command.KEY_UNIQUE_ID, Command.KEY_INDEX); } } case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "SA200CMD;{%s};02;Enable1\r", Command.KEY_UNIQUE_ID); + return formatCommand(command, prefix + ";%s;02;Enable1\r", Command.KEY_UNIQUE_ID); case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "SA200CMD;{%s};02;Disable1\r", Command.KEY_UNIQUE_ID); + return formatCommand(command, prefix + ";%s;02;Disable1\r", Command.KEY_UNIQUE_ID); case Command.TYPE_ALARM_ARM: - return formatCommand(command, "SA200CMD;{%s};02;Enable2\r", Command.KEY_UNIQUE_ID); + return formatCommand(command, prefix + ";%s;02;Enable2\r", Command.KEY_UNIQUE_ID); case Command.TYPE_ALARM_DISARM: - return formatCommand(command, "SA200CMD;{%s};02;Disable2\r", Command.KEY_UNIQUE_ID); + return formatCommand(command, prefix + ";%s;02;Disable2\r", Command.KEY_UNIQUE_ID); default: return null; } diff --git a/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java b/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java index 2607d7bd1..d218f63ce 100644 --- a/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java @@ -30,11 +30,11 @@ public class SviasProtocolEncoder extends StringProtocolEncoder { protected Object encodeCommand(Command command) { switch (command.getType()) { case Command.TYPE_CUSTOM: - return formatCommand(command, "{%s}", Command.KEY_DATA); + return formatCommand(command, "%s", Command.KEY_DATA); case Command.TYPE_POSITION_SINGLE: return formatCommand(command, "AT+STR=1*"); case Command.TYPE_SET_ODOMETER: - return formatCommand(command, "AT+ODT={%s}*", Command.KEY_DATA); + return formatCommand(command, "AT+ODT=%s*", Command.KEY_DATA); case Command.TYPE_ENGINE_STOP: return formatCommand(command, "AT+OUT=1,1*"); case Command.TYPE_ENGINE_RESUME: diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index c634d2438..cc2868a20 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -200,6 +200,9 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { case 9: position.set(Position.PREFIX_ADC + 1, readValue(buf, length, false)); break; + case 10: + position.set(Position.PREFIX_ADC + 2, readValue(buf, length, false)); + break; case 17: position.set("axisX", readValue(buf, length, true)); break; diff --git a/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java index a8aa84105..5d7e63920 100644 --- a/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java @@ -50,7 +50,7 @@ public class Tk103ProtocolEncoder extends StringProtocolEncoder { if (alternative) { switch (command.getType()) { case Command.TYPE_CUSTOM: - return formatAlt(command, "{%s}", Command.KEY_DATA); + return formatAlt(command, "%s", Command.KEY_DATA); case Command.TYPE_GET_VERSION: return formatAlt(command, "*about*"); case Command.TYPE_POWER_OFF: @@ -74,36 +74,36 @@ public class Tk103ProtocolEncoder extends StringProtocolEncoder { case Command.TYPE_ALARM_SOS: return formatAlt(command, command.getBoolean(Command.KEY_ENABLE) ? "*soson*" : "*sosoff*"); case Command.TYPE_SET_CONNECTION: - return formatAlt(command, "*setip*%s*{%s}*", - command.getString(Command.KEY_SERVER).replace(".", "*"), Command.KEY_PORT); + String server = command.getString(Command.KEY_SERVER).replace(".", "*"); + return formatAlt(command, "*setip*" + server + "*%s*", Command.KEY_PORT); case Command.TYPE_SOS_NUMBER: - return formatAlt(command, "*master*{%s}*{%s}*", Command.KEY_DEVICE_PASSWORD, Command.KEY_PHONE); + return formatAlt(command, "*master*%s*%s*", Command.KEY_DEVICE_PASSWORD, Command.KEY_PHONE); default: return null; } } else { switch (command.getType()) { case Command.TYPE_CUSTOM: - return formatCommand(command, "({%s}{%s})", Command.KEY_UNIQUE_ID, Command.KEY_DATA); + return formatCommand(command, "(%s%s)", Command.KEY_UNIQUE_ID, Command.KEY_DATA); case Command.TYPE_GET_VERSION: - return formatCommand(command, "({%s}AP07)", Command.KEY_UNIQUE_ID); + return formatCommand(command, "(%sAP07)", Command.KEY_UNIQUE_ID); case Command.TYPE_REBOOT_DEVICE: - return formatCommand(command, "({%s}AT00)", Command.KEY_UNIQUE_ID); + return formatCommand(command, "(%sAT00)", Command.KEY_UNIQUE_ID); case Command.TYPE_SET_ODOMETER: - return formatCommand(command, "({%s}AX01)", Command.KEY_UNIQUE_ID); + return formatCommand(command, "(%sAX01)", Command.KEY_UNIQUE_ID); case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "({%s}AP00)", Command.KEY_UNIQUE_ID); + return formatCommand(command, "(%sAP00)", Command.KEY_UNIQUE_ID); case Command.TYPE_POSITION_PERIODIC: - return formatCommand(command, "({%s}AR00%s0000)", Command.KEY_UNIQUE_ID, - String.format("%04X", command.getInteger(Command.KEY_FREQUENCY))); + String frequency = String.format("%04X", command.getInteger(Command.KEY_FREQUENCY)); + return formatCommand(command, "(%sAR00" + frequency + "0000)", Command.KEY_UNIQUE_ID); case Command.TYPE_POSITION_STOP: - return formatCommand(command, "({%s}AR0000000000)", Command.KEY_UNIQUE_ID); + return formatCommand(command, "(%sAR0000000000)", Command.KEY_UNIQUE_ID); case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "({%s}AV010)", Command.KEY_UNIQUE_ID); + return formatCommand(command, "(%sAV010)", Command.KEY_UNIQUE_ID); case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "({%s}AV011)", Command.KEY_UNIQUE_ID); + return formatCommand(command, "(%sAV011)", Command.KEY_UNIQUE_ID); case Command.TYPE_OUTPUT_CONTROL: - return formatCommand(command, "({%s}AV00{%s})", Command.KEY_UNIQUE_ID, Command.KEY_DATA); + return formatCommand(command, "(%sAV00%s)", Command.KEY_UNIQUE_ID, Command.KEY_DATA); default: return null; } diff --git a/src/main/java/org/traccar/protocol/TopinProtocol.java b/src/main/java/org/traccar/protocol/TopinProtocol.java new file mode 100644 index 000000000..844dd7518 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TopinProtocol.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TopinProtocol extends BaseProtocol { + + public TopinProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new TopinProtocolDecoder(TopinProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java new file mode 100644 index 000000000..ea72b7cb8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java @@ -0,0 +1,172 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; + +import java.net.SocketAddress; +import java.util.TimeZone; + +public class TopinProtocolDecoder extends BaseProtocolDecoder { + + public TopinProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_LOGIN = 0x01; + public static final int MSG_GPS = 0x10; + public static final int MSG_GPS_OFFLINE = 0x11; + public static final int MSG_STATUS = 0x13; + public static final int MSG_WIFI_OFFLINE = 0x17; + public static final int MSG_WIFI = 0x69; + + private void sendResponse(Channel channel, int type, ByteBuf content) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeShort(0x7878); + response.writeByte(1 + content.readableBytes()); + response.writeByte(type); + response.writeBytes(content); + response.writeByte('\r'); + response.writeByte('\n'); + content.release(); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + int length = buf.readUnsignedByte(); + + int type = buf.readUnsignedByte(); + + DeviceSession deviceSession; + if (type == MSG_LOGIN) { + String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); + deviceSession = getDeviceSession(channel, remoteAddress, imei); + ByteBuf content = Unpooled.buffer(); + content.writeByte(deviceSession != null ? 0x01 : 0x44); + sendResponse(channel, type, content); + return null; + } else { + deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + } + + if (type == MSG_GPS || type == MSG_GPS_OFFLINE) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + ByteBuf time = buf.slice(buf.readerIndex(), 6); + + Gt06ProtocolDecoder.decodeGps(position, buf, false, TimeZone.getTimeZone("UTC")); + + ByteBuf content = Unpooled.buffer(); + content.writeBytes(time); + sendResponse(channel, type, content); + + return position; + + } else if (type == MSG_STATUS) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + int battery = buf.readUnsignedByte(); + int firmware = buf.readUnsignedByte(); + int timezone = buf.readUnsignedByte(); + int interval = buf.readUnsignedByte(); + int signal = 0; + if (length >= 7) { + signal = buf.readUnsignedByte(); + position.set(Position.KEY_RSSI, signal); + } + + position.set(Position.KEY_BATTERY_LEVEL, battery); + position.set(Position.KEY_VERSION_FW, firmware); + + ByteBuf content = Unpooled.buffer(); + content.writeByte(battery); + content.writeByte(firmware); + content.writeByte(timezone); + content.writeByte(interval); + if (length >= 7) { + content.writeByte(signal); + } + sendResponse(channel, type, content); + + return position; + + } else if (type == MSG_WIFI || type == MSG_WIFI_OFFLINE) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + ByteBuf time = buf.readSlice(6); + + Network network = new Network(); + for (int i = 0; i < length; 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); + + ByteBuf content = Unpooled.buffer(); + content.writeBytes(time); + sendResponse(channel, type, content); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java b/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java index 3bbb92031..a96dd1ee3 100644 --- a/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java @@ -34,9 +34,9 @@ public class TotemProtocolEncoder extends StringProtocolEncoder { switch (command.getType()) { // Assuming PIN 8 (Output C) is the power wire, like manual says but it can be PIN 5,7,8 case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "*{%s},025,C,1#", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "*%s,025,C,1#", Command.KEY_DEVICE_PASSWORD); case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "*{%s},025,C,0#", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "*%s,025,C,0#", Command.KEY_DEVICE_PASSWORD); default: return null; } diff --git a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java index 873b22006..a17003fc8 100644 --- a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java @@ -171,12 +171,31 @@ public class UproProtocolDecoder extends BaseProtocolDecoder { position.setAltitude( Integer.parseInt(data.readSlice(6).toString(StandardCharsets.US_ASCII)) * 0.1); break; + case 'J': + if (data.readableBytes() == 6) { + char index = (char) data.readUnsignedByte(); + int status = data.readUnsignedByte(); + double value = Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)) * 0.1; + if (BitUtil.check(status, 0)) { + value = -value; + } + position.set(Position.PREFIX_TEMP + index, value); + } + break; case 'K': position.set("statusExtended", data.toString(StandardCharsets.US_ASCII)); break; case 'M': - position.set(Position.KEY_BATTERY_LEVEL, - Integer.parseInt(data.readSlice(3).toString(StandardCharsets.US_ASCII)) * 0.1); + if (data.readableBytes() == 3) { + position.set(Position.KEY_BATTERY_LEVEL, + Integer.parseInt(data.readSlice(3).toString(StandardCharsets.US_ASCII)) * 0.1); + } else if (data.readableBytes() == 4) { + char index = (char) data.readUnsignedByte(); + data.readUnsignedByte(); // status + position.set( + "humidity" + index, + Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII))); + } break; case 'N': position.set(Position.KEY_RSSI, diff --git a/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java b/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java index b433dfd2a..f285267ba 100644 --- a/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java @@ -137,33 +137,33 @@ public class WatchProtocolEncoder extends StringProtocolEncoder implements Strin case Command.TYPE_POSITION_SINGLE: return formatTextCommand(channel, command, "RG"); case Command.TYPE_SOS_NUMBER: - return formatTextCommand(channel, command, "SOS{%s},{%s}", Command.KEY_INDEX, Command.KEY_PHONE); + return formatTextCommand(channel, command, "SOS%s,%s", Command.KEY_INDEX, Command.KEY_PHONE); case Command.TYPE_ALARM_SOS: - return formatTextCommand(channel, command, "SOSSMS,{%s}", Command.KEY_ENABLE); + return formatTextCommand(channel, command, "SOSSMS,%s", Command.KEY_ENABLE); case Command.TYPE_ALARM_BATTERY: - return formatTextCommand(channel, command, "LOWBAT,{%s}", Command.KEY_ENABLE); + return formatTextCommand(channel, command, "LOWBAT,%s", Command.KEY_ENABLE); case Command.TYPE_REBOOT_DEVICE: return formatTextCommand(channel, command, "RESET"); case Command.TYPE_POWER_OFF: return formatTextCommand(channel, command, "POWEROFF"); case Command.TYPE_ALARM_REMOVE: - return formatTextCommand(channel, command, "REMOVE,{%s}", Command.KEY_ENABLE); + return formatTextCommand(channel, command, "REMOVE,%s", Command.KEY_ENABLE); case Command.TYPE_SILENCE_TIME: - return formatTextCommand(channel, command, "SILENCETIME,{%s}", Command.KEY_DATA); + return formatTextCommand(channel, command, "SILENCETIME,%s", Command.KEY_DATA); case Command.TYPE_ALARM_CLOCK: - return formatTextCommand(channel, command, "REMIND,{%s}", Command.KEY_DATA); + return formatTextCommand(channel, command, "REMIND,%s", Command.KEY_DATA); case Command.TYPE_SET_PHONEBOOK: - return formatTextCommand(channel, command, "PHB,{%s}", Command.KEY_DATA); + return formatTextCommand(channel, command, "PHB,%s", Command.KEY_DATA); case Command.TYPE_MESSAGE: - return formatTextCommand(channel, command, "MESSAGE,{%s}", Command.KEY_MESSAGE); + return formatTextCommand(channel, command, "MESSAGE,%s", Command.KEY_MESSAGE); case Command.TYPE_VOICE_MESSAGE: return formatBinaryCommand(channel, command, "TK,", getBinaryData(command)); case Command.TYPE_POSITION_PERIODIC: - return formatTextCommand(channel, command, "UPLOAD,{%s}", Command.KEY_FREQUENCY); + return formatTextCommand(channel, command, "UPLOAD,%s", Command.KEY_FREQUENCY); case Command.TYPE_SET_TIMEZONE: - return formatTextCommand(channel, command, "LZ,,{%s}", Command.KEY_TIMEZONE); + return formatTextCommand(channel, command, "LZ,%s,%s", Command.KEY_LANGUAGE, Command.KEY_TIMEZONE); case Command.TYPE_SET_INDICATOR: - return formatTextCommand(channel, command, "FLOWER,{%s}", Command.KEY_DATA); + return formatTextCommand(channel, command, "FLOWER,%s", Command.KEY_DATA); default: return null; } diff --git a/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java b/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java index c45edf00d..93086bf8a 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java @@ -32,11 +32,11 @@ public class WialonProtocolEncoder extends StringProtocolEncoder { case Command.TYPE_REBOOT_DEVICE: return formatCommand(command, "reboot\r\n"); case Command.TYPE_SEND_USSD: - return formatCommand(command, "USSD:{%s}\r\n", Command.KEY_PHONE); + return formatCommand(command, "USSD:%s\r\n", Command.KEY_PHONE); case Command.TYPE_IDENTIFICATION: return formatCommand(command, "VER?\r\n"); case Command.TYPE_OUTPUT_CONTROL: - return formatCommand(command, "L{%s}={%s}\r\n", Command.KEY_INDEX, Command.KEY_DATA); + return formatCommand(command, "L%s=%s\r\n", Command.KEY_INDEX, Command.KEY_DATA); default: return null; } diff --git a/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java b/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java index e9bb23d15..21f1ee321 100644 --- a/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java @@ -32,17 +32,17 @@ public class WondexProtocolEncoder extends StringProtocolEncoder { switch (command.getType()) { case Command.TYPE_REBOOT_DEVICE: - return formatCommand(command, "$WP+REBOOT={%s}", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "$WP+REBOOT=%s", Command.KEY_DEVICE_PASSWORD); case Command.TYPE_GET_DEVICE_STATUS: - return formatCommand(command, "$WP+TEST={%s}", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "$WP+TEST=%s", Command.KEY_DEVICE_PASSWORD); case Command.TYPE_GET_MODEM_STATUS: - return formatCommand(command, "$WP+GSMINFO={%s}", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "$WP+GSMINFO=%s", Command.KEY_DEVICE_PASSWORD); case Command.TYPE_IDENTIFICATION: - return formatCommand(command, "$WP+IMEI={%s}", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "$WP+IMEI=%s", Command.KEY_DEVICE_PASSWORD); case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "$WP+GETLOCATION={%s}", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "$WP+GETLOCATION=%s", Command.KEY_DEVICE_PASSWORD); case Command.TYPE_GET_VERSION: - return formatCommand(command, "$WP+VER={%s}", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "$WP+VER=%s", Command.KEY_DEVICE_PASSWORD); default: return null; } diff --git a/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java b/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java index fc849fe15..4f2707c2a 100644 --- a/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java @@ -32,9 +32,9 @@ public class XexunProtocolEncoder extends StringProtocolEncoder { switch (command.getType()) { case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "powercar{%s} 11", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "powercar%s 11", Command.KEY_DEVICE_PASSWORD); case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "powercar{%s} 00", Command.KEY_DEVICE_PASSWORD); + return formatCommand(command, "powercar%s 00", Command.KEY_DEVICE_PASSWORD); default: return null; } diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index d31cac534..fd5d55a50 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,11 +17,18 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttributes(decoder, binary( + "797900B2700000000102003500010400330012000000000000000000000000000000000000003400061354A48DFF00003400061154A48E56000011000A000000000000000000000001000803537601000282180002000802140743044211890003000A89340752000038689636001800020182002B000116002C000454A4FF350009000100000A0001010028000100002E000400000000002A00010000290004000000000030000A000101680014016802D00000B38F0D0A")); + verifyAttribute(decoder, binary( "78780c95130a071223200100013ad10d0a"), Position.KEY_ALARM, Position.ALARM_GENERAL); verifyAttribute(decoder, binary( + "78783c3400000000130a1906011105029b4d450b1828d5001c00000000009e7d014e140fc000004e990000000004c301a442210000020101c001c0000591aa0d"), + Position.PREFIX_ADC + 1, 4.48); + + verifyAttribute(decoder, binary( "797900a87000000001020035000101003300125d7e3a180600d504b598f708814b3a001d1500340006125d7e39dc000011000a012e02620000000000000001000803537601000129800002000803102608593397620003000a89012608522933976266001800020172002b000114002c00045d7df3c70009000106000a000109002800010d002e00040000f25d002a000111002900040000017e0030000a000100b4000a00b402d0000591250d0a"), Position.KEY_ALARM, Position.ALARM_REMOVING); diff --git a/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java index 31e4f2dee..687a2a68c 100644 --- a/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java @@ -14,6 +14,9 @@ public class H02ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, buffer( "*HQ,135790246811220,HTBT#")); + verifyPosition(decoder, buffer( + "*HQ,865205035331981,V1,132926,A,1935.3933,N,07920.4134,E, 3.34,342,280519,FFFFFFFF#")); + verifyPosition(decoder, binary( "24702802061601234020031910125482600612695044000000ffffbbff000000000000000001760d04e2c9934d")); diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index d4ae3b50c..8050d07a1 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -2,6 +2,7 @@ package org.traccar.protocol; import org.junit.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Position; public class HuabaoProtocolDecoderTest extends ProtocolTest { @@ -13,6 +14,13 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "7E01000021013345678906000F002C012F373031313142534A2D4D3742203030303030303001D4C1423838383838B47E")); + verifyAttribute(decoder, binary( + "7e02000054086031592715006e0000000000000002015a3c1a06c8733800000000000019103022183633362a4d30302c34352c31313338363030526f79314f70656e26303030303030303030303030263132333435363738393031323334353623ff7e"), + Position.KEY_BATTERY, 3.86); + + verifyPosition(decoder, binary( + "7e0200004e08026300003006480000000000000007021477d90841920700000000005019110515194001040000167130011631010cd00400000400d3020027d4013fd6143839363130313832303030343833363532383330da0104897e")); + verifyPosition(decoder, binary( "7e020000400303000002280042000000000000000301618ab406c31ec800000000000518092116145701040000047830011031010aeb16000c00b28986011780108622216500060089ffffffffc37e")); diff --git a/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java new file mode 100644 index 000000000..12f0106f9 --- /dev/null +++ b/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpMethod; +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class OutsafeProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + OutsafeProtocolDecoder decoder = new OutsafeProtocolDecoder(null); + + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("{\"device\":\"862061044762093\",\"owner\":\"\",\"data\":{\"cmd\":\"GEO\",\"ms1\":82,\"ms2\":80,\"ms3\":5266,\"ms4\":-68,\"observation\":\"$NMEA 323455\",\"content\":null},\"time\":null,\"origin\":\"TCP\",\"latitude\":19.334734,\"longitude\":-99.307236,\"altitude\":2000,\"heading\":0,\"rssi\":123}"))); + + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("{\"device\":\"1e09d88a-fe8e-4dee-90b9-6297088ff3de\",\"owner\":\"\",\"data\":{\"cmd\":\"GEO\",\"ms1\":82,\"ms2\":80,\"ms3\":5266,\"ms4\":-68,\"observation\":\"$NMEA 323455\",\"content\":null},\"time\":null,\"origin\":\"TCP\",\"latitude\":19.334734,\"longitude\":-99.307236,\"altitude\":2000,\"heading\":0,\"rssi\":123}"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java index 582ed9a5a..0fe3a3a01 100644 --- a/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java @@ -2,6 +2,7 @@ package org.traccar.protocol; import org.junit.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Position; public class PluginProtocolDecoderTest extends ProtocolTest { @@ -10,6 +11,13 @@ public class PluginProtocolDecoderTest extends ProtocolTest { PluginProtocolDecoder decoder = new PluginProtocolDecoder(null); + verifyAttribute(decoder, text( + "$$STATUS,60925,20190829123115,28.254151,-25.860605,0.0,0,0,-1,2,0.000,13699,0.00,0,0,28.4,23.4,0,0,0,0,0,0,0,0,0"), + Position.PREFIX_TEMP + 1, 28.4); + + verifyPosition(decoder, text( + "$$STATUS,60550,20191014084650,28.254258,-25.860355,0.0,236,0,-1,2,7472.967,13697,0.00,0,0,0.0,0.0,0,0,0,0,0,0,0,0,0")); + verifyPosition(decoder, text( "$$STATUS,fleet40,20190704122622,26.259431,-29.027889,0,9,0,-1,2,19719,805315969,0,0,0")); diff --git a/src/test/java/org/traccar/protocol/Pt215FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Pt215FrameDecoderTest.java deleted file mode 100644 index 2e3600b99..000000000 --- a/src/test/java/org/traccar/protocol/Pt215FrameDecoderTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.traccar.protocol; - -import org.junit.Test; -import org.traccar.ProtocolTest; - -public class Pt215FrameDecoderTest extends ProtocolTest { - - @Test - public void testDecode() throws Exception { - - Pt215FrameDecoder decoder = new Pt215FrameDecoder(); - - verifyFrame( - binary("58580d010359339075799656010d0a"), - decoder.decode(null, null, binary("58580d010359339075799656010d0a"))); - - verifyFrame( - binary("5858071340010819640d0a"), - decoder.decode(null, null, binary("5858071340010819640d0a"))); - - verifyFrame( - binary("585815101309160d0f0c9902b7015405f0e82404347afff7000d0a"), - decoder.decode(null, null, binary("585815101309160d0f0c9902b7015405f0e82404347afff7000d0a"))); - - } - -} diff --git a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java index a2cb021ef..4ab343876 100644 --- a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java @@ -13,6 +13,9 @@ public class SigfoxProtocolDecoderTest extends ProtocolTest { SigfoxProtocolDecoder decoder = new SigfoxProtocolDecoder(null); verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("{ \"device\" : \"33827B\", \"data\" : \"1f03198e63807f08836402ff\", \"time\" : \"1574346702\", \"snr\" : \"8.82\", \"station\" : \"140A\", \"avgSnr\" : \"11.28\", \"lat\" : \"52.0\", \"lng\" : \"-8.0\", \"rssi\" : \"-141.00\", \"seqNumber\" : \"3662\"}"))); + + verifyPosition(decoder, request(HttpMethod.POST, "/", buffer("{ \"device\": \"49F941\", \"location\": {\"lat\":19.48954345634299,\"lng\":-99.09340606338463,\"radius\":1983,\"source\":2,\"status\":1} }"))); verifyAttribute(decoder, request(HttpMethod.POST, "/", diff --git a/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java new file mode 100644 index 000000000..b040d4ecf --- /dev/null +++ b/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class SolarPoweredProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SolarPoweredProtocolDecoder decoder = new SolarPoweredProtocolDecoder(null); + + verifyPosition(decoder, binary( + "7e850256553304728011003e811319130b0b11211f01a2e6be091fa0e10114cc1582020f00831000004e7400000044000000223819020c84114161726f6e34475630312d313931303331127e")); + + verifyPosition(decoder, binary( + "7e850256553304728011003e811319130b0d160e2901a2e66f091fa0ab0014c39482020f0083100002f42c00000287000000fc2719021484114161726f6e34475630312d313931303331e67e")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java index ccd9139f4..1c84b5c89 100644 --- a/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java @@ -11,6 +11,10 @@ public class SuntechFrameDecoderTest extends ProtocolTest { SuntechFrameDecoder decoder = new SuntechFrameDecoder(); verifyFrame( + binary("81004e05200013383fffff3401000301130a0512080400000000000000000000000047f9d5846a06810072225214010100020300a8002604c1000004b000000470000025a100000000000025c4000000a6"), + decoder.decode(null, null, binary("81004e05200013383fffff3401000301130a0512080400000000000000000000000047f9d5846a06810072225214010100020300a8002604c1000004b000000470000025a100000000000025c4000000a6"))); + + verifyFrame( binary("5354363030414c563b303038373238333237"), decoder.decode(null, null, binary("5354363030414c563b3030383732383332370d"))); diff --git a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java index 304bc0fed..da1ef8ab4 100644 --- a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java @@ -15,13 +15,17 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { decoder.setIncludeAdc(true); decoder.setIncludeTemp(true); - verifyPosition(decoder, text( + verifyAttribute(decoder, buffer( + "ST600STT;008350848;35;523;20191102;13:49:46;0bf14fdb;334;20;2f19;57;+20.466737;-100.825455;000.006;000.00;11;1;10274175;11.36;00000000;1;0300;018353;4.2;1;0.00;;;;00000000000000;0;28EE56B911160234:+13.7;:;:"), + Position.PREFIX_TEMP + 2, 13.7); + + verifyPosition(decoder, buffer( "ST300STT;205173382;07;564;20160322;23:23:18;232e19;+19.288278;-099.128750;000.122;000.00;9;1;478391;11.53;000100;1;9498;079324;4.3;1;0.00;0.00;0.00;00000000000000;0;2898E16006000058:-20.8;2861626006000039:+2.5;:")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST300EVT;205173382;07;564;20160322;23:23:18;232e19;+19.288278;-099.128750;000.122;000.00;9;1;478391;11.53;000100;2;1;9498;079324;4.3;1;0.00;0.00;0.00;00000000000000;0;2898E16006000058:-20.8;2861626006000039:+2.5;:")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST600STT;008349958;35;523;20181112;00:49:30;0bf10d4e;334;20;2f19;22;+20.552718;-100.824478;050.021;095.41;12;1;1303603;14.30;10000000;4;8911;001987;4.1;0;0.00;;;;00000000000000;0;2826C8A70800000C:+26.6;:;:")); } @@ -34,7 +38,7 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { decoder.setHbm(true); decoder.setIncludeRpm(true); - verifyAttribute(decoder, text( + verifyAttribute(decoder, buffer( "ST300STT;907131077;04;706;20190227;23:59:34;cc719;-12.963490;-038.499587;000.067;000.00;7;1;57095;12.50;000000;1;0337;000207;0.0;1;0;012E717F010000;1"), Position.KEY_RPM, 0); @@ -47,7 +51,7 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { decoder.setHbm(true); - verifyAttribute(decoder, text( + verifyAttribute(decoder, buffer( "ST300ALT;007239104;40;313;20190112;01:07:16;c99139;+04.703287;-074.148897;000.000;189.72;21;1;425512;12.61;100000;33;003188;4.1;1"), Position.KEY_HOURS, 3188 * 60000L); @@ -58,135 +62,145 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { SuntechProtocolDecoder decoder = new SuntechProtocolDecoder(null); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( + "ST390STT;007579860;18;302;20191101;11:28:51;145b49;-23.267030;-047.298142;000.000;000.00;9;1;5;11.93;000000;2;0003;000002;4.03;0;20010000;22470;724;05;-58;5211;1")); + + verifyAttribute(decoder, binary( + "81004e05200013383fffff3401000300130b020b2a0500000000000000000000000047f9ec846a06500000000012010200000123a1002904ba00010fb40000000000000000000000000000000000005989"), + Position.KEY_IGNITION, false); + + verifyPosition(decoder, binary( + "81004e05200013383fffff3401000301130a0512080400000000000000000000000047f9d5846a06810072225214010100020300a8002604c1000004b000000470000025a100000000000025c4000000a6")); + + verifyPosition(decoder, buffer( "ALT;0520000295;3FFFFF;52;1.0.2;0;20190703;01:03:24;00004697;732;101;0002;59;+4.682583;-74.128142;0.00;0.00;6;1;00000000;00000000;9;1;;4.1;12.92;103188")); - verifyAttribute(decoder, text( + verifyAttribute(decoder, buffer( "ST300UEX;109003241;08;1026;20190425;17:36:04;04402;+04.722553;-074.052583;000.020;000.00;10;1;0;12.04;010000;51;CabAVL\"CabMensaje,0,58.5,-1.0,,,FinMensaje\"FinAVL\r\n;B1;0000000000;4.1;1"), "fuel1", 58.5); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST600UEX;008728327;20;520;20190218;10:56:51;0bf1a893;334;20;2f19;18;+20.514195;-100.743597;000.015;000.00;9;1;3720808;12.89;000000;44;t_0=0D;N_0=0551.0;t_1=14;N_1=039F.0;Q_D=0B\r\n;9E;010440;4.1;1")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST600UEX;100850000;01;010;20081017;07:41:56;0000004f;450;20;0023;24;+37.478519;+126.886819;000.012;000.00;9;1;0;15.30;001100;25;Welcome to Suntech World!;12;0;4.5;1")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST300STT;007238270;40;313;20190220;12:05:04;c99e48;+04.644623;-074.076922;010.390;202.77;20;1;997100;14.10;100000;2;8384;003634;4.1;1")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST300STT;109002029;08;1080;20190220;13:00:55;85405;+04.645710;-074.078525;007.760;005.19;10;1;6520802;13.86;100100;4;1716;0000039863;4.1;1;0.00;0000;0000;0;0")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "SA200STT;608945;129;20190215;15:04:53;3dce071558;+22.006721;-098.771016;001.198;000.00;11;1;2632589;12.21;010000;1;3211")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST410STT;007272376;408;01;10217;732;103;-87;51511;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;3.8;1;2503;6;20181031;20:12:58;+04.741277;-074.048238;052.375;189.87;20;1")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST410STT;007272376;408;01;21651;732;123;-65;1824;1;21654;732;123;1824;0;0;22542;732;123;1824;0;0;21656;732;123;1824;0;0;21655;732;123;1824;0;0;22541;732;123;1824;0;0;0;0;0;0;0;0;3.7;1;0156;1;20180816;05:18:52;+04.722322;-074.052776;000.074;000.00;10;1")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST600STT;008084783;20;419;20180308;18:00:36;0032cc3e;736;3;445c;41;-16.530023;-068.084267;018.640;267.99;10;1;11655;13.33;100000;2;0336;000061;4.5;0;0.00")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST600STT;107850496;20;419;20180227;14:30:45;00462b08;736;3;4524;50;-16.479091;-068.119119;000.346;000.00;4;1;0;13.89;000000;1;0223;000003;0.0;0;0.00")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST600STT;100850000;01;010;20081017;07:41:56;0000004f;450;20;0023;24;+37.478519;+126.886819;000.012;000.00;9;1;0;15.30;00110000;1;0072;0;4.5;1;12.35")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "STT;100850000;3FFFFF;26;010;1;20161117;08:37:39;0000004F;450;0;0014;20;+37.479323;+126.887827;62.03;65.43;10;1;00000101;00001000;1;2;0492")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "STT;6009999006;3FFFFF;26;398;0;20170827;20:04:37;087d4760;310;410;0ba0;23;+40.123420;-074.995971;000.031;000.00;8;1;00000001;00000000;1;1;0006")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST500STT;205450135;07;843;20170816;23:24:45;+19.338432;-099.179817;000.283;000.00;6;1;141121;12.89;0;0;1;4659;002.795;0;001.891;611;4.0")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST300STT;205170303;12;561;20170816;09:10:34;173f53;+19.082370;-098.214287;006.776;000.00;0;0;52982186;12.75;100000;2;6328;155747;4.2;1;0.00;0;0.00;0.00;00000000000000;0;28F2B7600600005D:+5.2;:;:")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST910;Location;205576803;500;20170319;12:18:17;-22.846014;-046.322176;000.000;000.00;0;3.8;0;1;9159")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST910;Emergency;205576803;500;20170319;12:15:22;-22.846014;-046.322176;000.000;000.00;0;2")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST910;Location;205576803;500;20170312;12:56:52;-22.846014;-046.322176;000.000;000.00;0;3.8;0;0;0019")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST300STT;100850000;01;010;20081017;07:41:56;00100;+37.478519;+126.886819;000.012;000.00;9;1;0;15.30;001100;1;0072;0;4.5;1;1750;012497F1160000;1;004f001454;450;00;-320;20;255;1")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST300STT;205589913;05;527;20170304;02:21:33;be139;-25.398868;-049.325636;000.476;000.00;6;1;427;12.57;100000010;1;0172;017.159;0;002.327;12;4.0")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "SA200STT;638947;803;20170117;07:40:44;5d309;-01.287213;-047.917462;000.035;000.00;10;1;2036194;12.57;000000;1;0376;010360;4.2;1")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST300ALT;205174410;14;712;20110101;00:00:07;00000;+20.593923;-100.336716;000.000;000.00;0;0;0;16.57;000000;81;000000;4.0;0;0.00;0000;0000;0;0")); - verifyNull(decoder, text( + verifyNull(decoder, buffer( "SA200ALV;317652")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST910;Alert;123456;410;20141018;18:30:12;+37.478774;+126.889690;000.000;000.00;0;4.0;1;6002"), position("2014-10-18 18:30:12.000", false, 37.47877, 126.88969)); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST910;Alert;123456;410;20141018;18:30:12;+37.478774;+126.889690;000.000;000.00;0;4.0;1;6002;02;0;0310000100;450;01;-282;70;255;3;0")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "SA200STT;317652;042;20120718;15:37:12;16d41;-15.618755;-056.083241;000.024;000.00;8;1;41548;12.17;100000;2;1979"), position("2012-07-18 15:37:12.000", true, -15.61876, -56.08324)); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "SA200STT;317652;042;20120721;19:04:30;16d41;-15.618743;-056.083221;000.001;000.00;12;1;41557;12.21;000000;1;3125")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "SA200STT;317652;042;20120722;00:24:23;4f310;-15.618767;-056.083214;000.011;000.00;11;1;41557;12.21;000000;1;3205")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "SA200STT;315198;042;20120808;20:37:34;3fac25;-15.618731;-056.083216;000.007;000.00;12;1;48;0.00;000000;1;0127")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "SA200STT;315198;042;20120809;13:43:34;4f310;-15.618709;-056.083223;000.025;000.00;8;1;49;12.10;100000;2;0231")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "SA200EMG;317652;042;20120718;15:35:41;16d41;-15.618740;-056.083252;000.034;000.00;8;1;41548;12.17;110000;1")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "SA200ALT;317652;042;20120829;14:25:58;16d41;-15.618770;-056.083242;000.029;000.00;0;0;2404240;0.00;000000;10")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "SA200STT;430070;133;20130615;22:22:32;151347;+02.860514;-060.653351;000.003;000.00;12;1;0;12.39;000000;1;0208")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST910;Location;344506;017;20130727;14:10:00;-25.398714;-049.296818;000.187;000.00;1;4.32;1;1;0001")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST300STT;205027329;03;374;20150108;17:54:42;177b38;-23.566052;-046.477588;000.000;000.00;0;0;0;12.11;000000;1;0312")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST910;Emergency;205283272;500;20150716;19:12:01;-23.659019;-046.695403;000.602;000.00;0;4.2;1;1;02;10820;2fdb090736;724;05;0;2311;255;0;100")); decoder.setProtocolType(1); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST910;Location;907510186;552;20180504;23:15:45;3af54e5331;+19.301833;-099.190657;000.246;000.00;1;28462;80;1;0;0423;02;334;05;-215;20051;1;4;100")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST910;Alert;485195;20170409;22:37:41;3be0133057;+24.882410;-107.509152;000.070;000.00;1;286734;72;02;295;05;-415;4912;255;10;10")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST910;Location;485195;528;20170410;01:18:57;f1dd134840;+24.787139;-107.434679;000.020;000.00;1;286734;100;1;0;0188;02;295;05;-339;4936;255;4;74")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST910;Location;560266;500;20161207;21:33:11;af910be101;-25.504234;-049.278003;000.080;000.00;1;10054889;70;1;1;1311;02;724;06;-317;3041;2;10;92")); - verifyPosition(decoder, text( + verifyPosition(decoder, buffer( "ST910;Emergency;238569;528;20170403;00:02:09;7574160020;+19.661292;-099.144473;000.176;000.00;1;228638;1")); } diff --git a/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java index d1dad8c92..82e0e0d88 100644 --- a/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java @@ -23,7 +23,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeEngineStop() throws Exception { + public void testEncodeEngineStop() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null); @@ -36,7 +36,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodePositionSingle() throws Exception { + public void testEncodePositionSingle() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null); @@ -49,7 +49,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodePositionPeriodic() throws Exception { + public void testEncodePositionPeriodic() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null); @@ -63,7 +63,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodePositionStop() throws Exception { + public void testEncodePositionStop() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null); @@ -76,7 +76,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeGetVersion() throws Exception { + public void testEncodeGetVersion() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null); @@ -89,7 +89,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeRebootDevice() throws Exception { + public void testEncodeRebootDevice() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null); @@ -102,7 +102,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeSetOdometer() throws Exception { + public void testEncodeSetOdometer() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null); @@ -115,7 +115,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodePositionSingleAlternative() throws Exception { + public void testEncodePositionSingleAlternative() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null, true); @@ -128,7 +128,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodePositionPeriodicAlternative() throws Exception { + public void testEncodePositionPeriodicAlternative() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null, true); @@ -141,7 +141,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodePositionStopAlternative() throws Exception { + public void testEncodePositionStopAlternative() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null, true); @@ -154,7 +154,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeGetVersionAlternative() throws Exception { + public void testEncodeGetVersionAlternative() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null, true); @@ -167,7 +167,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeRebootDeviceAlternative() throws Exception { + public void testEncodeRebootDeviceAlternative() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null, true); @@ -180,7 +180,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeIdentificationAlternative() throws Exception { + public void testEncodeIdentificationAlternative() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null, true); @@ -193,7 +193,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeSosOnAlternative() throws Exception { + public void testEncodeSosOnAlternative() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null, true); @@ -207,7 +207,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeSosOffAlternative() throws Exception { + public void testEncodeSosOffAlternative() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null, true); @@ -221,7 +221,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeCustom() throws Exception { + public void testEncodeCustom() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null); @@ -235,7 +235,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeCustomAlternative() throws Exception { + public void testEncodeCustomAlternative() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null, true); @@ -249,7 +249,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeSetConnectionAlternative() throws Exception { + public void testEncodeSetConnectionAlternative() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null, true); @@ -264,7 +264,7 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest { } @Test - public void testEncodeSosNumberAlternative() throws Exception { + public void testEncodeSosNumberAlternative() { Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(null, true); diff --git a/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java new file mode 100644 index 000000000..08bc8f699 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java @@ -0,0 +1,27 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TopinProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TopinProtocolDecoder decoder = new TopinProtocolDecoder(null); + + verifyNull(decoder, binary( + "78780d0103593390754169634d0d0a")); + + verifyNotNull(decoder, binary( + "7878001719111120141807019456465111aa3c465111ab464651c1a550465106b150465342f750465342f65a465111a95a000d0a")); + + verifyPosition(decoder, binary( + "787812100a03170f32179c026b3f3e0c22ad651f34600d0a")); + + verifyAttributes(decoder, binary( + "78780713514d0819640d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java index e43ff322e..e758725f2 100644 --- a/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class UproProtocolDecoderTest extends ProtocolTest { UproProtocolDecoder decoder = new UproProtocolDecoder(null); + verifyPosition(decoder, buffer( + "*HQ201861909268000132,BA&A1820223307024309650492530000311019&B0100000000&F0000&V0036&R0500&J000182&M0052&W00000091&I231026027BD39090827BD5ACA04&X(501E0)(B0000)(E0136)(J01E0)(L3)(k8937204016201240376F)&K00200&T85&N01#")); + verifyAttribute(decoder, buffer( "*VK200867282036729446,BA&A1759265051877702037465660022210819&B0000000000&W00&G000030&M830&N26&O1706&o11&T0783#"), Position.KEY_BATTERY_LEVEL, 83.0); diff --git a/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java index 798213c7b..a4a795050 100644 --- a/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java +++ b/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java @@ -78,6 +78,10 @@ public class WatchProtocolEncoderTest extends ProtocolTest { command.set(Command.KEY_TIMEZONE, "GMT-11:30"); verifyFrame(buffer("[CS*123456789012345*0009*LZ,,-11.5]"), encoder.encodeCommand(null, command)); + command.set(Command.KEY_LANGUAGE, 0); + command.set(Command.KEY_TIMEZONE, "GMT+05:45"); + verifyFrame(buffer("[CS*123456789012345*000a*LZ,0,+5.75]"), encoder.encodeCommand(null, command)); + } } |