diff options
Diffstat (limited to 'src/main/java')
164 files changed, 3550 insertions, 893 deletions
diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java index aa5be612e..e6e02c2d6 100644 --- a/src/main/java/org/traccar/BaseProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -86,7 +86,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { protected TimeZone getTimeZone(long deviceId, String defaultTimeZone) { TimeZone result = TimeZone.getTimeZone(defaultTimeZone); - String timeZoneName = identityManager.lookupAttributeString(deviceId, "decoder.timezone", null, true); + String timeZoneName = identityManager.lookupAttributeString(deviceId, "decoder.timezone", null, false, true); if (timeZoneName != null) { result = TimeZone.getTimeZone(timeZoneName); } else { @@ -143,7 +143,13 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { } public DeviceSession getDeviceSession(Channel channel, SocketAddress remoteAddress, String... uniqueIds) { + return getDeviceSession(channel, remoteAddress, false, uniqueIds); + } + + public DeviceSession getDeviceSession( + Channel channel, SocketAddress remoteAddress, boolean ignoreCache, String... uniqueIds) { if (channel != null && BasePipelineFactory.getHandler(channel.pipeline(), HttpRequestDecoder.class) != null + || ignoreCache || config.getBoolean(getProtocolName() + ".ignoreSessionCache") || config.getBoolean("decoder.ignoreSessionCache")) { long deviceId = findDeviceId(remoteAddress, uniqueIds); if (deviceId != 0) { diff --git a/src/main/java/org/traccar/BaseProtocolEncoder.java b/src/main/java/org/traccar/BaseProtocolEncoder.java index d7625e4b8..b6df07b98 100644 --- a/src/main/java/org/traccar/BaseProtocolEncoder.java +++ b/src/main/java/org/traccar/BaseProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,25 +22,32 @@ import io.netty.channel.ChannelPromise; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.model.Command; -import org.traccar.model.Device; public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(BaseProtocolEncoder.class); + private static final String PROTOCOL_UNKNOWN = "unknown"; + + private final Protocol protocol; + + public BaseProtocolEncoder(Protocol protocol) { + this.protocol = protocol; + } + + public String getProtocolName() { + return protocol != null ? protocol.getName() : PROTOCOL_UNKNOWN; + } + protected String getUniqueId(long deviceId) { return Context.getIdentityManager().getById(deviceId).getUniqueId(); } protected void initDevicePassword(Command command, String defaultPassword) { if (!command.getAttributes().containsKey(Command.KEY_DEVICE_PASSWORD)) { - Device device = Context.getIdentityManager().getById(command.getDeviceId()); - String password = device.getString(Command.KEY_DEVICE_PASSWORD); - if (password != null) { - command.set(Command.KEY_DEVICE_PASSWORD, password); - } else { - command.set(Command.KEY_DEVICE_PASSWORD, defaultPassword); - } + String password = Context.getIdentityManager() + .getDevicePassword(command.getDeviceId(), getProtocolName(), defaultPassword); + command.set(Command.KEY_DEVICE_PASSWORD, password); } } diff --git a/src/main/java/org/traccar/StringProtocolEncoder.java b/src/main/java/org/traccar/StringProtocolEncoder.java index 1945ae174..d9acce7f0 100644 --- a/src/main/java/org/traccar/StringProtocolEncoder.java +++ b/src/main/java/org/traccar/StringProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,10 @@ import java.util.Map; public abstract class StringProtocolEncoder extends BaseProtocolEncoder { + public StringProtocolEncoder(Protocol protocol) { + super(protocol); + } + public interface ValueFormatter { String formatValue(String key, Object value); } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index a000329e2..2c5dcefd5 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -197,8 +197,9 @@ public final class Keys { "time.protocols", String.class); /** - * Replaces coordinates with last known if change is less than a 'coordinates.error' meters. Helps to avoid - * coordinates jumps during parking period. + * Replaces coordinates with last known if change is less than a 'coordinates.minError' meters + * or more than a 'coordinates.maxError' meters. Helps to avoid coordinates jumps during parking period + * or jumps to zero coordinates. */ public static final ConfigKey COORDINATES_FILTER = new ConfigKey( "coordinates.filter", Boolean.class); @@ -214,7 +215,7 @@ public final class Keys { * Position is also marked as 'invalid'. */ public static final ConfigKey COORDINATES_MAX_ERROR = new ConfigKey( - "filter.maxError", Integer.class); + "coordinates.maxError", Integer.class); /** * Enable to save device IP addresses information. Disabled by default. diff --git a/src/main/java/org/traccar/database/ConnectionManager.java b/src/main/java/org/traccar/database/ConnectionManager.java index 8bae1ea93..dd0071143 100644 --- a/src/main/java/org/traccar/database/ConnectionManager.java +++ b/src/main/java/org/traccar/database/ConnectionManager.java @@ -157,7 +157,7 @@ public class ConnectionManager { event = Main.getInjector().getInstance(OverspeedEventHandler.class) .updateOverspeedState(deviceState, Context.getDeviceManager(). - lookupAttributeDouble(deviceId, OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT, 0, false)); + lookupAttributeDouble(deviceId, OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT, 0, true, false)); if (event != null) { result.putAll(event); } diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index de4607d1f..fa95adeb2 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -29,6 +29,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.Context; +import org.traccar.model.Command; import org.traccar.model.Device; import org.traccar.model.DeviceState; import org.traccar.model.DeviceAccumulators; @@ -114,6 +115,24 @@ public class DeviceManager extends BaseObjectManager<Device> implements Identity return devicesByUniqueId.get(uniqueId); } + @Override + public String getDevicePassword(long id, String protocol, String defaultPassword) { + + String password = lookupAttributeString(id, Command.KEY_DEVICE_PASSWORD, null, false, false); + if (password != null) { + return password; + } + + if (protocol != null) { + password = Context.getConfig().getString(protocol + "." + Command.KEY_DEVICE_PASSWORD); + if (password != null) { + return password; + } + } + + return defaultPassword; + } + public Device getDeviceByPhone(String phone) { return devicesByPhone.get(phone); } @@ -312,8 +331,8 @@ public class DeviceManager extends BaseObjectManager<Device> implements Identity @Override public boolean lookupAttributeBoolean( - long deviceId, String attributeName, boolean defaultValue, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupConfig); + long deviceId, String attributeName, boolean defaultValue, boolean lookupServer, boolean lookupConfig) { + Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig); if (result != null) { return result instanceof String ? Boolean.parseBoolean((String) result) : (Boolean) result; } @@ -322,14 +341,15 @@ public class DeviceManager extends BaseObjectManager<Device> implements Identity @Override public String lookupAttributeString( - long deviceId, String attributeName, String defaultValue, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupConfig); + long deviceId, String attributeName, String defaultValue, boolean lookupServer, boolean lookupConfig) { + Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig); return result != null ? (String) result : defaultValue; } @Override - public int lookupAttributeInteger(long deviceId, String attributeName, int defaultValue, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupConfig); + public int lookupAttributeInteger( + long deviceId, String attributeName, int defaultValue, boolean lookupServer, boolean lookupConfig) { + Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig); if (result != null) { return result instanceof String ? Integer.parseInt((String) result) : ((Number) result).intValue(); } @@ -338,8 +358,8 @@ public class DeviceManager extends BaseObjectManager<Device> implements Identity @Override public long lookupAttributeLong( - long deviceId, String attributeName, long defaultValue, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupConfig); + long deviceId, String attributeName, long defaultValue, boolean lookupServer, boolean lookupConfig) { + Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig); if (result != null) { return result instanceof String ? Long.parseLong((String) result) : ((Number) result).longValue(); } @@ -347,15 +367,15 @@ public class DeviceManager extends BaseObjectManager<Device> implements Identity } public double lookupAttributeDouble( - long deviceId, String attributeName, double defaultValue, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupConfig); + long deviceId, String attributeName, double defaultValue, boolean lookupServer, boolean lookupConfig) { + Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig); if (result != null) { return result instanceof String ? Double.parseDouble((String) result) : ((Number) result).doubleValue(); } return defaultValue; } - private Object lookupAttribute(long deviceId, String attributeName, boolean lookupConfig) { + private Object lookupAttribute(long deviceId, String attributeName, boolean lookupServer, boolean lookupConfig) { Object result = null; Device device = getById(deviceId); if (device != null) { @@ -375,13 +395,12 @@ public class DeviceManager extends BaseObjectManager<Device> implements Identity } } } - if (result == null) { - if (lookupConfig) { - result = Context.getConfig().getString(attributeName); - } else { - Server server = Context.getPermissionsManager().getServer(); - result = server.getAttributes().get(attributeName); - } + if (result == null && lookupServer) { + Server server = Context.getPermissionsManager().getServer(); + result = server.getAttributes().get(attributeName); + } + if (result == null && lookupConfig) { + result = Context.getConfig().getString(attributeName); } } return result; diff --git a/src/main/java/org/traccar/database/IdentityManager.java b/src/main/java/org/traccar/database/IdentityManager.java index 6228a0f75..af6a6ce71 100644 --- a/src/main/java/org/traccar/database/IdentityManager.java +++ b/src/main/java/org/traccar/database/IdentityManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,18 +26,25 @@ public interface IdentityManager { Device getByUniqueId(String uniqueId) throws Exception; + String getDevicePassword(long id, String protocol, String defaultPassword); + Position getLastPosition(long deviceId); boolean isLatestPosition(Position position); - boolean lookupAttributeBoolean(long deviceId, String attributeName, boolean defaultValue, boolean lookupConfig); + boolean lookupAttributeBoolean( + long deviceId, String attributeName, boolean defaultValue, boolean lookupServer, boolean lookupConfig); - String lookupAttributeString(long deviceId, String attributeName, String defaultValue, boolean lookupConfig); + String lookupAttributeString( + long deviceId, String attributeName, String defaultValue, boolean lookupServer, boolean lookupConfig); - int lookupAttributeInteger(long deviceId, String attributeName, int defaultValue, boolean lookupConfig); + int lookupAttributeInteger( + long deviceId, String attributeName, int defaultValue, boolean lookupServer, boolean lookupConfig); - long lookupAttributeLong(long deviceId, String attributeName, long defaultValue, boolean lookupConfig); + long lookupAttributeLong( + long deviceId, String attributeName, long defaultValue, boolean lookupServer, boolean lookupConfig); - double lookupAttributeDouble(long deviceId, String attributeName, double defaultValue, boolean lookupConfig); + double lookupAttributeDouble( + long deviceId, String attributeName, double defaultValue, boolean lookupServer, boolean lookupConfig); } diff --git a/src/main/java/org/traccar/handler/CopyAttributesHandler.java b/src/main/java/org/traccar/handler/CopyAttributesHandler.java index 6a0966d33..3cd7d144d 100644 --- a/src/main/java/org/traccar/handler/CopyAttributesHandler.java +++ b/src/main/java/org/traccar/handler/CopyAttributesHandler.java @@ -33,7 +33,7 @@ public class CopyAttributesHandler extends BaseDataHandler { @Override protected Position handlePosition(Position position) { String attributesString = identityManager.lookupAttributeString( - position.getDeviceId(), "processing.copyAttributes", "", true); + position.getDeviceId(), "processing.copyAttributes", "", false, true); if (attributesString.isEmpty()) { attributesString = Position.KEY_DRIVER_UNIQUE_ID; } else { diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index dceaede01..7cd9153c1 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -130,7 +130,7 @@ public class FilterHandler extends BaseDataHandler { private boolean skipAttributes(Position position) { if (skipAttributes) { String attributesString = Context.getIdentityManager().lookupAttributeString( - position.getDeviceId(), "filter.skipAttributes", "", true); + position.getDeviceId(), "filter.skipAttributes", "", false, true); for (String attribute : attributesString.split("[ ,]")) { if (position.getAttributes().containsKey(attribute)) { return true; diff --git a/src/main/java/org/traccar/handler/GeolocationHandler.java b/src/main/java/org/traccar/handler/GeolocationHandler.java index c7b39e491..0e78322c8 100644 --- a/src/main/java/org/traccar/handler/GeolocationHandler.java +++ b/src/main/java/org/traccar/handler/GeolocationHandler.java @@ -65,7 +65,6 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter { position.setAltitude(0); position.setSpeed(0); position.setCourse(0); - position.set(Position.KEY_RSSI, 0); ctx.fireChannelRead(position); } diff --git a/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java b/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java index 59de61bba..bc1426b86 100644 --- a/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java +++ b/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java @@ -47,7 +47,7 @@ public class FuelDropEventHandler extends BaseEventHandler { } double fuelDropThreshold = identityManager - .lookupAttributeDouble(device.getId(), ATTRIBUTE_FUEL_DROP_THRESHOLD, 0, false); + .lookupAttributeDouble(device.getId(), ATTRIBUTE_FUEL_DROP_THRESHOLD, 0, true, false); if (fuelDropThreshold > 0) { Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java index 157bb64e0..e534df9de 100644 --- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java +++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java @@ -120,7 +120,7 @@ public class OverspeedEventHandler extends BaseEventHandler { return null; } - double speedLimit = deviceManager.lookupAttributeDouble(deviceId, ATTRIBUTE_SPEED_LIMIT, 0, false); + double speedLimit = deviceManager.lookupAttributeDouble(deviceId, ATTRIBUTE_SPEED_LIMIT, 0, true, false); double geofenceSpeedLimit = 0; long overspeedGeofenceId = 0; diff --git a/src/main/java/org/traccar/helper/DateBuilder.java b/src/main/java/org/traccar/helper/DateBuilder.java index 6e1b779f0..9752f6977 100644 --- a/src/main/java/org/traccar/helper/DateBuilder.java +++ b/src/main/java/org/traccar/helper/DateBuilder.java @@ -69,7 +69,9 @@ public class DateBuilder { public DateBuilder setCurrentDate() { Calendar now = Calendar.getInstance(calendar.getTimeZone()); - return setYear(now.get(Calendar.YEAR)).setMonth(now.get(Calendar.MONTH)).setDay(now.get(Calendar.DAY_OF_MONTH)); + return setYear(now.get(Calendar.YEAR)) + .setMonth(now.get(Calendar.MONTH) + 1) + .setDay(now.get(Calendar.DAY_OF_MONTH)); } public DateBuilder setHour(int hour) { diff --git a/src/main/java/org/traccar/model/Network.java b/src/main/java/org/traccar/model/Network.java index 2d56950f1..4d67fc5d8 100644 --- a/src/main/java/org/traccar/model/Network.java +++ b/src/main/java/org/traccar/model/Network.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -30,6 +30,10 @@ public class Network { addCellTower(cellTower); } + public Network(WifiAccessPoint wifiAccessPoint) { + addWifiAccessPoint(wifiAccessPoint); + } + private Integer homeMobileCountryCode; public Integer getHomeMobileCountryCode() { diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java index 6032dc588..2c0e22c9e 100644 --- a/src/main/java/org/traccar/model/Position.java +++ b/src/main/java/org/traccar/model/Position.java @@ -82,6 +82,9 @@ public class Position extends Message { public static final String KEY_BLOCKED = "blocked"; public static final String KEY_DOOR = "door"; public static final String KEY_AXLE_WEIGHT = "axleWeight"; + public static final String KEY_G_SENSOR = "gSensor"; + public static final String KEY_ICCID = "iccid"; + public static final String KEY_PHONE = "phone"; public static final String KEY_DTCS = "dtcs"; public static final String KEY_OBD_SPEED = "obdSpeed"; // knots diff --git a/src/main/java/org/traccar/protocol/AdmProtocol.java b/src/main/java/org/traccar/protocol/AdmProtocol.java index 08f932ceb..93b1e355a 100644 --- a/src/main/java/org/traccar/protocol/AdmProtocol.java +++ b/src/main/java/org/traccar/protocol/AdmProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ public class AdmProtocol extends BaseProtocol { protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 1, -3, 0, true)); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new AdmProtocolEncoder()); + pipeline.addLast(new AdmProtocolEncoder(AdmProtocol.this)); pipeline.addLast(new AdmProtocolDecoder(AdmProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java b/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java index e76bc2ddc..1c3dfc156 100644 --- a/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) * Copyright 2017 Anatoliy Golubev (darth.naihil@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,9 +18,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class AdmProtocolEncoder extends StringProtocolEncoder { + public AdmProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java b/src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java index 57af5e366..3c43ddf2a 100644 --- a/src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,15 +17,11 @@ package org.traccar.protocol; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; import org.traccar.model.Position; import java.net.SocketAddress; @@ -134,9 +130,11 @@ public class AquilaProtocolDecoder extends BaseProtocolDecoder { .number("xx") // checksum .compile(); - private Position decodeA(Channel channel, SocketAddress remoteAddress, String sentence) { + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - Parser parser = new Parser(PATTERN_A, sentence); + Parser parser = new Parser(PATTERN_A, (String) msg); if (!parser.matches()) { return null; } @@ -218,186 +216,4 @@ public class AquilaProtocolDecoder extends BaseProtocolDecoder { return position; } - private static final Pattern PATTERN_B_1 = new PatternBuilder() - .text("$") - .expression("[^,]+,") // header - .expression("[^,]+,") // client - .expression("[^,]+,") // firmware version - .expression(".{2},") // packet type - .number("d+,") // message id - .expression("[LH],") // status - .number("(d+),") // imei - .expression("[^,]+,") // registration number - .number("([01]),") // validity - .number("(dd)(dd)(dddd),") // date (ddmmyyyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(-?d+.d+),") // latitude - .expression("([NS]),") - .number("(-?d+.d+),") // longitude - .expression("([EW]),") - .number("(d+.d+),") // speed - .number("(d+),") // course - .number("(d+),") // satellites - .number("(-?d+.d+),") // altitude - .number("(d+.d+),") // pdop - .number("(d+.d+),") // hdop - .expression("[^,]+,") // operator - .number("([01]),") // ignition - .number("([01]),") // charge - .number("(d+.d+),") // power - .number("(d+.d+),") // battery - .number("([01]),") // emergency - .expression("[CO],") // tamper - .number("(d+),") // rssi - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(x+),") // lac - .number("(x+),") // cid - .number("(d+),(x+),(x+),") // cell 1 - .number("(d+),(x+),(x+),") // cell 2 - .number("(d+),(x+),(x+),") // cell 3 - .number("(d+),(x+),(x+),") // cell 4 - .number("([01])+,") // inputs - .number("([01])+,") // outputs - .number("d+,") // frame number - .number("(d+.d+),") // adc1 - .number("(d+.d+),") // adc2 - .number("d+,") // delta distance - .any() - .compile(); - - private static final Pattern PATTERN_B_2 = new PatternBuilder() - .text("$") - .expression("[^,]+,") // header - .expression("[^,]+,") // client - .expression("(.{3}),") // message type - .number("(d+),") // imei - .expression(".{2},") // packet type - .number("(dd)(dd)(dddd)") // date (ddmmyyyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([AV]),") // validity - .number("(-?d+.d+),") // latitude - .expression("([NS]),") - .number("(-?d+.d+),") // longitude - .expression("([EW]),") - .number("(-?d+.d+),") // altitude - .number("(d+.d+),") // speed - .any() - .compile(); - - private Position decodeB2(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_B_2, sentence); - if (!parser.matches()) { - return null; - } - - String type = parser.next(); - String id = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setAltitude(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - - if (type.equals("EMR") && channel != null) { - String password = Context.getIdentityManager().lookupAttributeString( - deviceSession.getDeviceId(), getProtocolName() + ".password", "aquila123", true); - channel.writeAndFlush(new NetworkMessage( - "#set$" + id + "@" + password + "#EMR_MODE:0*", remoteAddress)); - } - - return position; - } - - private Position decodeB1(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_B_1, sentence); - if (!parser.matches()) { - return null; - } - - String id = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(parser.nextInt() == 1); - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - position.setCourse(parser.nextInt()); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - - position.setAltitude(parser.nextDouble()); - - position.set(Position.KEY_PDOP, parser.nextDouble()); - position.set(Position.KEY_HDOP, parser.nextDouble()); - position.set(Position.KEY_IGNITION, parser.nextInt() == 1); - position.set(Position.KEY_CHARGE, parser.nextInt() == 1); - position.set(Position.KEY_POWER, parser.nextDouble()); - position.set(Position.KEY_BATTERY, parser.nextDouble()); - - if (parser.nextInt() == 1) { - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - } - - Network network = new Network(); - - int rssi = parser.nextInt(); - int mcc = parser.nextInt(); - int mnc = parser.nextInt(); - - network.addCellTower(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt(), rssi)); - for (int i = 0; i < 4; i++) { - rssi = parser.nextInt(); - network.addCellTower(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt(), rssi)); - } - - position.setNetwork(network); - - position.set(Position.KEY_INPUT, parser.nextBinInt()); - position.set(Position.KEY_OUTPUT, parser.nextBinInt()); - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); - - return position; - } - - private Position decodeB(Channel channel, SocketAddress remoteAddress, String sentence) { - if (sentence.contains("EMR") || sentence.contains("SEM")) { - return decodeB2(channel, remoteAddress, sentence); - } else { - return decodeB1(channel, remoteAddress, sentence); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.startsWith("$$")) { - return decodeA(channel, remoteAddress, sentence); - } else { - return decodeB(channel, remoteAddress, sentence); - } - } - } diff --git a/src/main/java/org/traccar/protocol/AtrackProtocol.java b/src/main/java/org/traccar/protocol/AtrackProtocol.java index 8e5cfe9ff..429708b26 100644 --- a/src/main/java/org/traccar/protocol/AtrackProtocol.java +++ b/src/main/java/org/traccar/protocol/AtrackProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,14 +29,14 @@ public class AtrackProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new AtrackFrameDecoder()); - pipeline.addLast(new AtrackProtocolEncoder()); + pipeline.addLast(new AtrackProtocolEncoder(AtrackProtocol.this)); pipeline.addLast(new AtrackProtocolDecoder(AtrackProtocol.this)); } }); addServer(new TrackerServer(true, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new AtrackProtocolEncoder()); + pipeline.addLast(new AtrackProtocolEncoder(AtrackProtocol.this)); pipeline.addLast(new AtrackProtocolDecoder(AtrackProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java index 71bb6791c..53f04234d 100644 --- a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -84,6 +84,10 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { this.custom = custom; } + public void setForm(String form) { + this.form = form; + } + private static void sendResponse(Channel channel, SocketAddress remoteAddress, long rawId, int index) { if (channel != null) { ByteBuf response = Unpooled.buffer(12); @@ -156,7 +160,7 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_THROTTLE, Integer.parseInt(values[i])); break; case "ET": - position.set(Position.PREFIX_TEMP + 1, Integer.parseInt(values[i])); + position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(values[i])); break; case "FL": position.set(Position.KEY_FUEL_LEVEL, Integer.parseInt(values[i])); @@ -167,6 +171,36 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { case "AV1": position.set(Position.PREFIX_ADC + 1, Integer.parseInt(values[i])); break; + case "CD": + position.set(Position.KEY_ICCID, values[i]); + break; + case "EH": + position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(Integer.parseInt(values[i]) * 0.1)); + break; + case "IA": + position.set("intakeTemp", Integer.parseInt(values[i])); + break; + case "EL": + position.set(Position.KEY_ENGINE_LOAD, Integer.parseInt(values[i])); + break; + case "HA": + if (Integer.parseInt(values[i]) > 0) { + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + } + break; + case "HB": + if (Integer.parseInt(values[i]) > 0) { + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + } + break; + case "HC": + if (Integer.parseInt(values[i]) > 0) { + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + } + break; + case "MT": + position.set(Position.KEY_MOTION, Integer.parseInt(values[i]) > 0); + break; default: break; } @@ -274,7 +308,7 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // pending code status break; case "CD": - readString(buf); // sim cid + position.set(Position.KEY_ICCID, readString(buf)); break; case "CM": buf.readLong(); // imsi diff --git a/src/main/java/org/traccar/protocol/AtrackProtocolEncoder.java b/src/main/java/org/traccar/protocol/AtrackProtocolEncoder.java index 1e085cb26..d803ae391 100644 --- a/src/main/java/org/traccar/protocol/AtrackProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/AtrackProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -18,11 +18,16 @@ package org.traccar.protocol; import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; import java.nio.charset.StandardCharsets; public class AtrackProtocolEncoder extends BaseProtocolEncoder { + public AtrackProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java b/src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java index 16a31162a..37836ad5f 100644 --- a/src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 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. @@ -48,17 +48,19 @@ public class AvemaProtocolDecoder extends BaseProtocolDecoder { .number("(d+),") // event .number("(d+.d+),") // odometer .number("(d+),") // input - .number("(d+.d+)V,") // adc 1 - .number("(d+.d+)V,") // adc 2 + .number("(d+.d+)V?,") // adc 1 + .number("(d+.d+)V?,") // adc 2 .number("(d+),") // output .number("(d),") // roaming .number("(d+),") // rssi .number("d,") // communication system - .number("(ddd)") // mcc - .number("(dd),") // mnc + .number("(ddd)-?") // mcc + .number("(d+),") // mnc .number("(x+),") // lac .number("(x+),") // cid + .number("(d+.d+),").optional() // battery .number("([^,]+)?") // rfid + .any() .compile(); @Override @@ -99,6 +101,7 @@ public class AvemaProtocolDecoder extends BaseProtocolDecoder { position.setNetwork(new Network(CellTower.from( parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt(), rssi))); + position.set(Position.KEY_BATTERY, parser.nextDouble()); position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); return position; diff --git a/src/main/java/org/traccar/protocol/BceProtocol.java b/src/main/java/org/traccar/protocol/BceProtocol.java index 6453a05a9..c5e1dd04c 100644 --- a/src/main/java/org/traccar/protocol/BceProtocol.java +++ b/src/main/java/org/traccar/protocol/BceProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ public class BceProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new BceFrameDecoder()); - pipeline.addLast(new BceProtocolEncoder()); + pipeline.addLast(new BceProtocolEncoder(BceProtocol.this)); pipeline.addLast(new BceProtocolDecoder(BceProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java index ad7271f2f..30f9bb1f3 100644 --- a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java @@ -29,6 +29,7 @@ import org.traccar.model.Network; import org.traccar.model.Position; import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.LinkedList; import java.util.List; @@ -106,31 +107,31 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // acceleration pedal } if (BitUtil.check(mask, 2)) { - buf.readUnsignedIntLE(); // total fuel used + position.set(Position.KEY_FUEL_USED, buf.readUnsignedIntLE()); } if (BitUtil.check(mask, 3)) { - buf.readUnsignedByte(); // fuel level + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte()); } if (BitUtil.check(mask, 4)) { - buf.readUnsignedShortLE(); // engine speed + position.set(Position.KEY_RPM, buf.readUnsignedShortLE()); } if (BitUtil.check(mask, 5)) { - buf.readUnsignedIntLE(); // total hours + position.set(Position.KEY_HOURS, buf.readUnsignedIntLE()); } if (BitUtil.check(mask, 6)) { - buf.readUnsignedIntLE(); // total distance + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); } if (BitUtil.check(mask, 7)) { - buf.readUnsignedByte(); // engine coolant + position.set(Position.KEY_COOLANT_TEMP, (int) buf.readByte()); } if (BitUtil.check(mask, 8)) { - buf.readUnsignedByte(); // fuel level 2 + position.set("fuel2", buf.readUnsignedByte()); } if (BitUtil.check(mask, 9)) { - buf.readUnsignedByte(); // engine load + position.set(Position.KEY_ENGINE_LOAD, buf.readUnsignedByte()); } if (BitUtil.check(mask, 10)) { - buf.readUnsignedShortLE(); // service distance + position.set(Position.KEY_ODOMETER_SERVICE, buf.readUnsignedShortLE()); } if (BitUtil.check(mask, 11)) { buf.skipBytes(8); // sensors @@ -142,7 +143,7 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { buf.skipBytes(8); // trailer id } if (BitUtil.check(mask, 14)) { - buf.readUnsignedShortLE(); // fuel rate + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShortLE()); } } @@ -152,10 +153,10 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedShortLE(); // fuel economy } if (BitUtil.check(mask, 1)) { - buf.readUnsignedIntLE(); // fuel consumption + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedIntLE()); } if (BitUtil.check(mask, 2)) { - buf.readUnsignedMediumLE(); // axle weight + position.set(Position.KEY_AXLE_WEIGHT, buf.readUnsignedMediumLE()); } if (BitUtil.check(mask, 3)) { buf.readUnsignedByte(); // mil status @@ -169,6 +170,70 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(mask, 6)) { position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readLongLE())); } + if (BitUtil.check(mask, 7)) { + buf.readUnsignedShortLE(); // dallas temperature + } + if (BitUtil.check(mask, 8)) { + buf.readUnsignedShortLE(); // dallas humidity + } + if (BitUtil.check(mask, 9)) { + buf.skipBytes(6); // lls group 1 + } + if (BitUtil.check(mask, 10)) { + buf.skipBytes(6); // lls group 2 + } + if (BitUtil.check(mask, 11)) { + buf.skipBytes(21); // j1979 group 1 + } + if (BitUtil.check(mask, 12)) { + buf.skipBytes(20); // j1979 dtc + } + if (BitUtil.check(mask, 13)) { + buf.skipBytes(9); // j1708 group 1 + } + if (BitUtil.check(mask, 14)) { + buf.skipBytes(21); // driving quality + } + } + + private void decodeMask4(ByteBuf buf, int mask, Position position) { + + if (BitUtil.check(mask, 0)) { + buf.readUnsignedIntLE(); + } + if (BitUtil.check(mask, 1)) { + buf.skipBytes(30); // lls group 3 + } + if (BitUtil.check(mask, 2)) { + buf.readUnsignedIntLE(); // instant fuel consumption + } + if (BitUtil.check(mask, 3)) { + buf.skipBytes(10); // axle weight group + } + if (BitUtil.check(mask, 4)) { + buf.readUnsignedByte(); + } + if (BitUtil.check(mask, 5)) { + buf.readUnsignedShortLE(); + } + if (BitUtil.check(mask, 6)) { + buf.readUnsignedByte(); // maximum acceleration + buf.readUnsignedByte(); // maximum deceleration + buf.readUnsignedByte(); // maximum cornering + } + if (BitUtil.check(mask, 7)) { + buf.skipBytes(16); + } + if (BitUtil.check(mask, 8)) { + buf.skipBytes(40); // temperature sensors + } + if (BitUtil.check(mask, 9)) { + position.set("driver1", buf.readCharSequence(16, StandardCharsets.US_ASCII).toString().trim()); + position.set("driver2", buf.readCharSequence(16, StandardCharsets.US_ASCII).toString().trim()); + } + if (BitUtil.check(mask, 10)) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + } } @Override @@ -230,6 +295,11 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { mask = masks.get(2); decodeMask3(buf, mask, position); } + + if (masks.size() >= 4) { + mask = masks.get(3); + decodeMask4(buf, mask, position); + } } buf.readerIndex(structEnd); diff --git a/src/main/java/org/traccar/protocol/BceProtocolEncoder.java b/src/main/java/org/traccar/protocol/BceProtocolEncoder.java index 1bbf3db12..53ac51581 100644 --- a/src/main/java/org/traccar/protocol/BceProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/BceProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,9 +20,14 @@ import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; import org.traccar.helper.Checksum; import org.traccar.model.Command; +import org.traccar.Protocol; public class BceProtocolEncoder extends BaseProtocolEncoder { + public BceProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java b/src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java index 31416d7f1..dad0ae774 100644 --- a/src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -153,7 +153,7 @@ public class CalAmpProtocolDecoder extends BaseProtocolDecoder { int content = buf.readUnsignedByte(); if (BitUtil.check(content, 0)) { - String id = ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte())); + String id = ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte())).replace("f", ""); getDeviceSession(channel, remoteAddress, id); } diff --git a/src/main/java/org/traccar/protocol/CarcellProtocol.java b/src/main/java/org/traccar/protocol/CarcellProtocol.java index 0c305efcb..f08ab3bd9 100644 --- a/src/main/java/org/traccar/protocol/CarcellProtocol.java +++ b/src/main/java/org/traccar/protocol/CarcellProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -35,7 +35,7 @@ public class CarcellProtocol extends BaseProtocol { pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r')); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new CarcellProtocolEncoder()); + pipeline.addLast(new CarcellProtocolEncoder(CarcellProtocol.this)); pipeline.addLast(new CarcellProtocolDecoder(CarcellProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java b/src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java index 344b2f1ea..ec640ba71 100644 --- a/src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java @@ -155,7 +155,7 @@ public class CarcellProtocolDecoder extends BaseProtocolDecoder { Double mainVoltage = parser.nextDouble(0) / 100d; position.set(Position.KEY_POWER, mainVoltage); - position.set("iccid", parser.next()); + position.set(Position.KEY_ICCID, parser.next()); } return position; diff --git a/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java b/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java index e8f0081a0..083fe9a9e 100644 --- a/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -17,9 +17,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class CarcellProtocolEncoder extends StringProtocolEncoder { + public CarcellProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/CastelProtocol.java b/src/main/java/org/traccar/protocol/CastelProtocol.java index 9b854afc3..44c52d68f 100644 --- a/src/main/java/org/traccar/protocol/CastelProtocol.java +++ b/src/main/java/org/traccar/protocol/CastelProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,14 +32,14 @@ public class CastelProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, -4, 0, true)); - pipeline.addLast(new CastelProtocolEncoder()); + pipeline.addLast(new CastelProtocolEncoder(CastelProtocol.this)); pipeline.addLast(new CastelProtocolDecoder(CastelProtocol.this)); } }); addServer(new TrackerServer(true, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CastelProtocolEncoder()); + pipeline.addLast(new CastelProtocolEncoder(CastelProtocol.this)); pipeline.addLast(new CastelProtocolDecoder(CastelProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java index 0541adf6f..03e4b25fd 100644 --- a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,6 +84,7 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder { public static final short MSG_SC_HEARTBEAT_RESPONSE = (short) 0x9003; public static final short MSG_SC_GPS = 0x4001; public static final short MSG_SC_PID_DATA = 0x4002; + public static final short MSG_SC_G_SENSOR = 0x4003; public static final short MSG_SC_SUPPORTED_PID = 0x4004; public static final short MSG_SC_OBD_DATA = 0x4005; public static final short MSG_SC_DTCS_PASSENGER = 0x4006; @@ -290,152 +291,179 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder { Channel channel, SocketAddress remoteAddress, ByteBuf buf, int version, ByteBuf id, short type, DeviceSession deviceSession) { - if (type == MSG_SC_HEARTBEAT) { - - sendResponse(channel, remoteAddress, version, id, MSG_SC_HEARTBEAT_RESPONSE, null); - - } else if (type == MSG_SC_LOGIN || type == MSG_SC_LOGOUT || type == MSG_SC_GPS - || type == MSG_SC_ALARM || type == MSG_SC_CURRENT_LOCATION || type == MSG_SC_FUEL) { - - if (type == MSG_SC_LOGIN) { - ByteBuf response = Unpooled.buffer(10); - response.writeIntLE(0xFFFFFFFF); - response.writeShortLE(0); - response.writeIntLE((int) (System.currentTimeMillis() / 1000)); - sendResponse(channel, remoteAddress, version, id, MSG_SC_LOGIN_RESPONSE, response); - } - - if (type == MSG_SC_GPS) { - buf.readUnsignedByte(); // historical - } else if (type == MSG_SC_ALARM) { - buf.readUnsignedIntLE(); // alarm - } else if (type == MSG_SC_CURRENT_LOCATION) { - buf.readUnsignedShortLE(); - } - - buf.readUnsignedIntLE(); // ACC ON time - buf.readUnsignedIntLE(); // UTC time - long odometer = buf.readUnsignedIntLE(); - long tripOdometer = buf.readUnsignedIntLE(); - long fuelConsumption = buf.readUnsignedIntLE(); - buf.readUnsignedShortLE(); // current fuel consumption - long status = buf.readUnsignedIntLE(); - buf.skipBytes(8); - - int count = buf.readUnsignedByte(); + Position position; + int count; + + switch (type) { + + case MSG_SC_HEARTBEAT: + sendResponse(channel, remoteAddress, version, id, MSG_SC_HEARTBEAT_RESPONSE, null); + return null; + + case MSG_SC_LOGIN: + case MSG_SC_LOGOUT: + case MSG_SC_GPS: + case MSG_SC_ALARM: + case MSG_SC_CURRENT_LOCATION: + case MSG_SC_FUEL: + if (type == MSG_SC_LOGIN) { + ByteBuf response = Unpooled.buffer(10); + response.writeIntLE(0xFFFFFFFF); + response.writeShortLE(0); + response.writeIntLE((int) (System.currentTimeMillis() / 1000)); + sendResponse(channel, remoteAddress, version, id, MSG_SC_LOGIN_RESPONSE, response); + } - List<Position> positions = new LinkedList<>(); + if (type == MSG_SC_GPS) { + buf.readUnsignedByte(); // historical + } else if (type == MSG_SC_ALARM) { + buf.readUnsignedIntLE(); // alarm + } else if (type == MSG_SC_CURRENT_LOCATION) { + buf.readUnsignedShortLE(); + } - for (int i = 0; i < count; i++) { - Position position = readPosition(deviceSession, buf); - position.set(Position.KEY_ODOMETER, odometer); - position.set(Position.KEY_ODOMETER_TRIP, tripOdometer); - position.set(Position.KEY_FUEL_CONSUMPTION, fuelConsumption); - position.set(Position.KEY_STATUS, status); - positions.add(position); - } + buf.readUnsignedIntLE(); // ACC ON time + buf.readUnsignedIntLE(); // UTC time + long odometer = buf.readUnsignedIntLE(); + long tripOdometer = buf.readUnsignedIntLE(); + long fuelConsumption = buf.readUnsignedIntLE(); + buf.readUnsignedShortLE(); // current fuel consumption + long status = buf.readUnsignedIntLE(); + buf.skipBytes(8); + + count = buf.readUnsignedByte(); + + List<Position> positions = new LinkedList<>(); + + for (int i = 0; i < count; i++) { + position = readPosition(deviceSession, buf); + position.set(Position.KEY_ODOMETER, odometer); + position.set(Position.KEY_ODOMETER_TRIP, tripOdometer); + position.set(Position.KEY_FUEL_CONSUMPTION, fuelConsumption); + position.set(Position.KEY_STATUS, status); + positions.add(position); + } - if (type == MSG_SC_ALARM) { - int alarmCount = buf.readUnsignedByte(); - for (int i = 0; i < alarmCount; i++) { - if (buf.readUnsignedByte() != 0) { - int alarm = buf.readUnsignedByte(); - for (Position position : positions) { - decodeAlarm(position, alarm); + if (type == MSG_SC_ALARM) { + int alarmCount = buf.readUnsignedByte(); + for (int i = 0; i < alarmCount; i++) { + if (buf.readUnsignedByte() != 0) { + int alarm = buf.readUnsignedByte(); + for (Position p : positions) { + decodeAlarm(p, alarm); + } + buf.readUnsignedShortLE(); // description + buf.readUnsignedShortLE(); // threshold } - buf.readUnsignedShortLE(); // description - buf.readUnsignedShortLE(); // threshold + } + } else if (type == MSG_SC_FUEL) { + for (Position p : positions) { + p.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); } } - } else if (type == MSG_SC_FUEL) { - for (Position position : positions) { - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); - } - } - if (!positions.isEmpty()) { - return positions; - } + return positions.isEmpty() ? null : positions; - } else if (type == MSG_SC_GPS_SLEEP) { + case MSG_SC_GPS_SLEEP: + buf.readUnsignedIntLE(); // device time + return readPosition(deviceSession, buf); - buf.readUnsignedIntLE(); // device time + case MSG_SC_AGPS_REQUEST: + return readPosition(deviceSession, buf); - return readPosition(deviceSession, buf); + case MSG_SC_PID_DATA: + position = createPosition(deviceSession); - } else if (type == MSG_SC_AGPS_REQUEST) { + decodeStat(position, buf); - return readPosition(deviceSession, buf); + buf.readUnsignedShortLE(); // sample rate + decodeObd(position, buf, true); - } else if (type == MSG_SC_PID_DATA) { + return position; - Position position = createPosition(deviceSession); + case MSG_SC_G_SENSOR: + position = createPosition(deviceSession); - decodeStat(position, buf); + decodeStat(position, buf); - buf.readUnsignedShortLE(); // sample rate - decodeObd(position, buf, true); + buf.readUnsignedShortLE(); // sample rate - return position; + count = buf.readUnsignedByte(); - } else if (type == MSG_SC_DTCS_PASSENGER) { + StringBuilder data = new StringBuilder("["); + for (int i = 0; i < count; i++) { + if (i > 0) { + data.append(","); + } + data.append("["); + data.append(buf.readShortLE() * 0.015625); + data.append(","); + data.append(buf.readShortLE() * 0.015625); + data.append(","); + data.append(buf.readShortLE() * 0.015625); + data.append("]"); + } + data.append("]"); - Position position = createPosition(deviceSession); + position.set(Position.KEY_G_SENSOR, data.toString()); - decodeStat(position, buf); + return position; - buf.readUnsignedByte(); // flag - position.add(ObdDecoder.decodeCodes(ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte())))); + case MSG_SC_DTCS_PASSENGER: + position = createPosition(deviceSession); - return position; + decodeStat(position, buf); - } else if (type == MSG_SC_OBD_DATA) { + buf.readUnsignedByte(); // flag + position.add(ObdDecoder.decodeCodes(ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte())))); - Position position = createPosition(deviceSession); + return position; - decodeStat(position, buf); + case MSG_SC_OBD_DATA: + position = createPosition(deviceSession); - buf.readUnsignedByte(); // flag - decodeObd(position, buf, false); + decodeStat(position, buf); - return position; + buf.readUnsignedByte(); // flag + decodeObd(position, buf, false); - } else if (type == MSG_SC_CELL) { + return position; - Position position = createPosition(deviceSession); + case MSG_SC_CELL: + position = createPosition(deviceSession); - decodeStat(position, buf); + decodeStat(position, buf); - position.setNetwork(new Network( - CellTower.fromLacCid(buf.readUnsignedShortLE(), buf.readUnsignedShortLE()))); + position.setNetwork(new Network( + CellTower.fromLacCid(buf.readUnsignedShortLE(), buf.readUnsignedShortLE()))); - return position; + return position; - } else if (type == MSG_SC_QUERY_RESPONSE) { + case MSG_SC_QUERY_RESPONSE: + position = createPosition(deviceSession); - Position position = createPosition(deviceSession); + buf.readUnsignedShortLE(); // index + buf.readUnsignedByte(); // response count + buf.readUnsignedByte(); // response index - buf.readUnsignedShortLE(); // index - buf.readUnsignedByte(); // response count - buf.readUnsignedByte(); // response index + int failureCount = buf.readUnsignedByte(); + for (int i = 0; i < failureCount; i++) { + buf.readUnsignedShortLE(); // tag + } - int failureCount = buf.readUnsignedByte(); - for (int i = 0; i < failureCount; i++) { - buf.readUnsignedShortLE(); // tag - } + int successCount = buf.readUnsignedByte(); + for (int i = 0; i < successCount; i++) { + buf.readUnsignedShortLE(); // tag + position.set(Position.KEY_RESULT, + buf.readSlice(buf.readUnsignedShortLE()).toString(StandardCharsets.US_ASCII)); + } - int successCount = buf.readUnsignedByte(); - for (int i = 0; i < successCount; i++) { - buf.readUnsignedShortLE(); // tag - position.set(Position.KEY_RESULT, - buf.readSlice(buf.readUnsignedShortLE()).toString(StandardCharsets.US_ASCII)); - } + return position; - return position; + default: + return null; } - - return null; } private Object decodeCc( diff --git a/src/main/java/org/traccar/protocol/CastelProtocolEncoder.java b/src/main/java/org/traccar/protocol/CastelProtocolEncoder.java index e1f78e7c1..dc694da28 100644 --- a/src/main/java/org/traccar/protocol/CastelProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/CastelProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 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. @@ -21,11 +21,16 @@ import org.traccar.BaseProtocolEncoder; import org.traccar.Context; import org.traccar.helper.Checksum; import org.traccar.model.Command; +import org.traccar.Protocol; import java.nio.charset.StandardCharsets; public class CastelProtocolEncoder extends BaseProtocolEncoder { + public CastelProtocolEncoder(Protocol protocol) { + super(protocol); + } + private ByteBuf encodeContent(long deviceId, short type, ByteBuf content) { ByteBuf buf = Unpooled.buffer(0); diff --git a/src/main/java/org/traccar/protocol/CellocatorProtocol.java b/src/main/java/org/traccar/protocol/CellocatorProtocol.java index a52170dc9..d910877cf 100644 --- a/src/main/java/org/traccar/protocol/CellocatorProtocol.java +++ b/src/main/java/org/traccar/protocol/CellocatorProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,14 +29,14 @@ public class CellocatorProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new CellocatorFrameDecoder()); - pipeline.addLast(new CellocatorProtocolEncoder()); + pipeline.addLast(new CellocatorProtocolEncoder(CellocatorProtocol.this)); pipeline.addLast(new CellocatorProtocolDecoder(CellocatorProtocol.this)); } }); addServer(new TrackerServer(true, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CellocatorProtocolEncoder()); + pipeline.addLast(new CellocatorProtocolEncoder(CellocatorProtocol.this)); pipeline.addLast(new CellocatorProtocolDecoder(CellocatorProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java index 14d14f4b6..aa13a0aa2 100644 --- a/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java @@ -43,29 +43,52 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_SERVER_ACKNOWLEDGE = 4; - private byte commandCount; + public static ByteBuf encodeContent(int type, int uniqueId, int packetNumber, ByteBuf content) { + + ByteBuf buf = Unpooled.buffer(); + buf.writeByte('M'); + buf.writeByte('C'); + buf.writeByte('G'); + buf.writeByte('P'); + buf.writeByte(type); + buf.writeIntLE(uniqueId); + buf.writeByte(packetNumber); + buf.writeIntLE(0); // authentication code + buf.writeBytes(content); + + byte checksum = 0; + for (int i = 4; i < buf.writerIndex(); i++) { + checksum += buf.getByte(i); + } + buf.writeByte(checksum); + + return buf; + } private void sendResponse(Channel channel, SocketAddress remoteAddress, long deviceId, byte packetNumber) { if (channel != null) { - ByteBuf reply = Unpooled.buffer(28); - reply.writeByte('M'); - reply.writeByte('C'); - reply.writeByte('G'); - reply.writeByte('P'); - reply.writeByte(MSG_SERVER_ACKNOWLEDGE); - reply.writeIntLE((int) deviceId); - reply.writeByte(commandCount++); - reply.writeIntLE(0); // authentication code - reply.writeByte(0); - reply.writeByte(packetNumber); - reply.writeZero(11); - - byte checksum = 0; - for (int i = 4; i < 27; i++) { - checksum += reply.getByte(i); - } - reply.writeByte(checksum); + ByteBuf content = Unpooled.buffer(); + content.writeByte(0); + content.writeByte(packetNumber); + content.writeZero(11); + ByteBuf reply = encodeContent(MSG_SERVER_ACKNOWLEDGE, (int) deviceId, packetNumber, content); + channel.writeAndFlush(new NetworkMessage(reply, remoteAddress)); + } + } + + private void sendModuleResponse(Channel channel, SocketAddress remoteAddress, long deviceId, byte packetNumber) { + if (channel != null) { + ByteBuf content = Unpooled.buffer(); + content.writeByte(0x80); + content.writeShortLE(10); // modules length + content.writeIntLE(0); // reserved + content.writeByte(9); // ack module type + content.writeShortLE(3); // module length + content.writeByte(0); // ack + content.writeShortLE(0); // reserved + + ByteBuf reply = encodeContent(MSG_CLIENT_MODULAR_EXT, (int) deviceId, packetNumber, content); channel.writeAndFlush(new NetworkMessage(reply, remoteAddress)); } } @@ -225,7 +248,11 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder { } byte packetNumber = buf.readByte(); - sendResponse(channel, remoteAddress, deviceUniqueId, packetNumber); + if (type == MSG_CLIENT_MODULAR_EXT) { + sendModuleResponse(channel, remoteAddress, deviceUniqueId, packetNumber); + } else { + sendResponse(channel, remoteAddress, deviceUniqueId, packetNumber); + } if (type == MSG_CLIENT_STATUS) { return decodeStatus(buf, deviceSession, alternative); diff --git a/src/main/java/org/traccar/protocol/CellocatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/CellocatorProtocolEncoder.java index 0382dbbc7..76fa67686 100644 --- a/src/main/java/org/traccar/protocol/CellocatorProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/CellocatorProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -19,27 +19,26 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class CellocatorProtocolEncoder extends BaseProtocolEncoder { - private ByteBuf encodeContent(long deviceId, int command, int data1, int data2) { + public CellocatorProtocolEncoder(Protocol protocol) { + super(protocol); + } + + public static ByteBuf encodeContent(int type, int uniqueId, int packetNumber, ByteBuf content) { - ByteBuf buf = Unpooled.buffer(0); + ByteBuf buf = Unpooled.buffer(); buf.writeByte('M'); buf.writeByte('C'); buf.writeByte('G'); buf.writeByte('P'); - buf.writeByte(0); - buf.writeIntLE(Integer.parseInt(getUniqueId(deviceId))); - buf.writeByte(0); // command numerator + buf.writeByte(type); + buf.writeIntLE(uniqueId); + buf.writeByte(packetNumber); buf.writeIntLE(0); // authentication code - buf.writeByte(command); - buf.writeByte(command); - buf.writeByte(data1); - buf.writeByte(data1); - buf.writeByte(data2); - buf.writeByte(data2); - buf.writeIntLE(0); // command specific data + buf.writeBytes(content); byte checksum = 0; for (int i = 4; i < buf.writerIndex(); i++) { @@ -50,6 +49,23 @@ public class CellocatorProtocolEncoder extends BaseProtocolEncoder { return buf; } + private ByteBuf encodeCommand(long deviceId, int command, int data1, int data2) { + + ByteBuf content = Unpooled.buffer(); + content.writeByte(command); + content.writeByte(command); + content.writeByte(data1); + content.writeByte(data1); + content.writeByte(data2); + content.writeByte(data2); + content.writeIntLE(0); // command specific data + + ByteBuf buf = encodeContent(0, Integer.parseInt(getUniqueId(deviceId)), 0, content); + content.release(); + + return buf; + } + @Override protected Object encodeCommand(Command command) { @@ -57,7 +73,7 @@ public class CellocatorProtocolEncoder extends BaseProtocolEncoder { case Command.TYPE_OUTPUT_CONTROL: int data = Integer.parseInt(command.getString(Command.KEY_DATA)) << 4 + command.getInteger(Command.KEY_INDEX); - return encodeContent(command.getDeviceId(), 0x03, data, 0); + return encodeCommand(command.getDeviceId(), 0x03, data, 0); default: return null; } diff --git a/src/main/java/org/traccar/protocol/CityeasyProtocol.java b/src/main/java/org/traccar/protocol/CityeasyProtocol.java index f4b49c9ff..8ab4ce93a 100644 --- a/src/main/java/org/traccar/protocol/CityeasyProtocol.java +++ b/src/main/java/org/traccar/protocol/CityeasyProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,7 @@ public class CityeasyProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0)); - pipeline.addLast(new CityeasyProtocolEncoder()); + pipeline.addLast(new CityeasyProtocolEncoder(CityeasyProtocol.this)); pipeline.addLast(new CityeasyProtocolDecoder(CityeasyProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/CityeasyProtocolEncoder.java b/src/main/java/org/traccar/protocol/CityeasyProtocolEncoder.java index 350fdf0ab..934105862 100644 --- a/src/main/java/org/traccar/protocol/CityeasyProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/CityeasyProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,9 +22,14 @@ import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; import org.traccar.helper.Checksum; import org.traccar.model.Command; +import org.traccar.Protocol; public class CityeasyProtocolEncoder extends BaseProtocolEncoder { + public CityeasyProtocolEncoder(Protocol protocol) { + super(protocol); + } + private ByteBuf encodeContent(int type, ByteBuf content) { ByteBuf buf = Unpooled.buffer(); diff --git a/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java b/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java index c49f06d65..58a5a88e3 100644 --- a/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -208,6 +208,7 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder { position.set("solarPower", buf.readUnsignedShortLE() * 0.001); break; default: + buf.readUnsignedShortLE(); // other break; } } diff --git a/src/main/java/org/traccar/protocol/EelinkProtocol.java b/src/main/java/org/traccar/protocol/EelinkProtocol.java index de4ea971b..8a055d643 100644 --- a/src/main/java/org/traccar/protocol/EelinkProtocol.java +++ b/src/main/java/org/traccar/protocol/EelinkProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,14 +34,14 @@ public class EelinkProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2)); - pipeline.addLast(new EelinkProtocolEncoder(false)); + pipeline.addLast(new EelinkProtocolEncoder(EelinkProtocol.this, false)); pipeline.addLast(new EelinkProtocolDecoder(EelinkProtocol.this)); } }); addServer(new TrackerServer(true, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new EelinkProtocolEncoder(true)); + pipeline.addLast(new EelinkProtocolEncoder(EelinkProtocol.this, true)); pipeline.addLast(new EelinkProtocolDecoder(EelinkProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java index a6fd94b83..41d76f37f 100644 --- a/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java @@ -412,7 +412,8 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder { return decodeNew(deviceSession, buf, type, index); - } else if (type == MSG_HEARTBEAT && buf.readableBytes() >= 2) { + } else if (type == MSG_HEARTBEAT && buf.readableBytes() >= 2 + || type == MSG_OBD && buf.readableBytes() == 4) { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); diff --git a/src/main/java/org/traccar/protocol/EelinkProtocolEncoder.java b/src/main/java/org/traccar/protocol/EelinkProtocolEncoder.java index 8f33441fb..3673c35b3 100644 --- a/src/main/java/org/traccar/protocol/EelinkProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/EelinkProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -20,6 +20,7 @@ import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; import org.traccar.helper.DataConverter; import org.traccar.model.Command; +import org.traccar.Protocol; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -28,7 +29,8 @@ public class EelinkProtocolEncoder extends BaseProtocolEncoder { private boolean connectionless; - public EelinkProtocolEncoder(boolean connectionless) { + public EelinkProtocolEncoder(Protocol protocol, boolean connectionless) { + super(protocol); this.connectionless = connectionless; } diff --git a/src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java b/src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java index b9fcb2f44..9f0baf6b2 100644 --- a/src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 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. @@ -39,6 +39,8 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder { super(protocol); } + private boolean useObjectIdAsDeviceId = true; + public static final int PT_RESPONSE = 0; public static final int PT_APPDATA = 1; public static final int PT_SIGNED_APPDATA = 2; @@ -68,7 +70,7 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_ABS_CNTR_DATA = 25; public static final int MSG_ABS_LOOPIN_DATA = 26; public static final int MSG_LIQUID_LEVEL_SENSOR = 27; - public static final int MSG_PASSENGERS_COUNTERS = 28; + public static final int MSG_PASSENGERS_COUNTERS = 28; private int packetId; @@ -121,11 +123,18 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder { ByteBuf buf = (ByteBuf) msg; + List<Position> positions = new LinkedList<>(); + + short headerLength = buf.getUnsignedByte(buf.readerIndex() + 3); int index = buf.getUnsignedShort(buf.readerIndex() + 5 + 2); - buf.skipBytes(buf.getUnsignedByte(buf.readerIndex() + 3)); + short packetType = buf.getUnsignedByte(buf.readerIndex() + 5 + 2 + 2); + buf.skipBytes(headerLength); - List<Position> positions = new LinkedList<>(); + if (packetType == PT_RESPONSE) { + return null; + } + long objectId = 0L; while (buf.readableBytes() > 2) { int length = buf.readUnsignedShortLE(); @@ -133,7 +142,7 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder { int recordFlags = buf.readUnsignedByte(); if (BitUtil.check(recordFlags, 0)) { - buf.readUnsignedIntLE(); // object id + objectId = buf.readUnsignedIntLE(); } if (BitUtil.check(recordFlags, 1)) { @@ -164,6 +173,7 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder { int end = buf.readUnsignedShortLE() + buf.readerIndex(); if (type == MSG_TERM_IDENTITY) { + useObjectIdAsDeviceId = false; buf.readUnsignedIntLE(); // object id int flags = buf.readUnsignedByte(); @@ -254,8 +264,16 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder { buf.readerIndex(end); } - if (serviceType == SERVICE_TELEDATA && deviceSession != null) { - positions.add(position); + if (serviceType == SERVICE_TELEDATA && position.getValid()) { + if (useObjectIdAsDeviceId && objectId != 0L) { + deviceSession = getDeviceSession(channel, remoteAddress, true, String.valueOf(objectId)); + if (deviceSession != null) { + position.setDeviceId(deviceSession.getDeviceId()); + } + } + if (deviceSession != null) { + positions.add(position); + } } } diff --git a/src/main/java/org/traccar/protocol/EnforaProtocol.java b/src/main/java/org/traccar/protocol/EnforaProtocol.java index f78e4b377..e462ab322 100644 --- a/src/main/java/org/traccar/protocol/EnforaProtocol.java +++ b/src/main/java/org/traccar/protocol/EnforaProtocol.java @@ -32,14 +32,14 @@ public class EnforaProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 2, -2, 2)); - pipeline.addLast(new EnforaProtocolEncoder()); + pipeline.addLast(new EnforaProtocolEncoder(EnforaProtocol.this)); pipeline.addLast(new EnforaProtocolDecoder(EnforaProtocol.this)); } }); addServer(new TrackerServer(true, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new EnforaProtocolEncoder()); + pipeline.addLast(new EnforaProtocolEncoder(EnforaProtocol.this)); pipeline.addLast(new EnforaProtocolDecoder(EnforaProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/EnforaProtocolEncoder.java b/src/main/java/org/traccar/protocol/EnforaProtocolEncoder.java index a46e6367d..8cc24dc0f 100644 --- a/src/main/java/org/traccar/protocol/EnforaProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/EnforaProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) * Copyright 2017 Jose Castellanos * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,11 +20,16 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; import java.nio.charset.StandardCharsets; public class EnforaProtocolEncoder extends StringProtocolEncoder { + public EnforaProtocolEncoder(Protocol protocol) { + super(protocol); + } + private ByteBuf encodeContent(String content) { ByteBuf buf = Unpooled.buffer(); diff --git a/src/main/java/org/traccar/protocol/EsealProtocol.java b/src/main/java/org/traccar/protocol/EsealProtocol.java index 7a27c617d..fc1d342e1 100644 --- a/src/main/java/org/traccar/protocol/EsealProtocol.java +++ b/src/main/java/org/traccar/protocol/EsealProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 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. @@ -36,7 +36,7 @@ public class EsealProtocol extends BaseProtocol { pipeline.addLast(new LineBasedFrameDecoder(1024)); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new EsealProtocolEncoder()); + pipeline.addLast(new EsealProtocolEncoder(EsealProtocol.this)); pipeline.addLast(new EsealProtocolDecoder(EsealProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java b/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java index b9bcc5b0a..6ee305ed8 100644 --- a/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 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. @@ -17,9 +17,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class EsealProtocolEncoder extends StringProtocolEncoder { + public EsealProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocol.java b/src/main/java/org/traccar/protocol/FifotrackProtocol.java index d1c3cf695..4a0a12ed3 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocol.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocol.java @@ -32,7 +32,7 @@ public class FifotrackProtocol extends BaseProtocol { protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new FifotrackFrameDecoder()); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new FifotrackProtocolEncoder()); + pipeline.addLast(new FifotrackProtocolEncoder(FifotrackProtocol.this)); pipeline.addLast(new FifotrackProtocolDecoder(FifotrackProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java index 2e728a918..40e146e0b 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -60,7 +60,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { .number("(-?d+),") // altitude .number("(d+),") // odometer .number("d+,") // runtime - .number("(xxxx),") // status + .number("(x{4,8}),") // status .number("(x+)?,") // input .number("(x+)?,") // output .number("(d+)|") // mcc @@ -69,7 +69,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { .number("(x+),") // cid .number("([x|]+)") // adc .expression(",([^,]+)") // rfid - .expression(",([^*]+)").optional(2) // sensors + .expression(",([^*]*)").optional(2) // sensors .any() .compile(); @@ -105,6 +105,24 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { } } + private String decodeAlarm(Integer alarm) { + if (alarm != null) { + switch (alarm) { + case 2: + return Position.ALARM_SOS; + case 14: + return Position.ALARM_LOW_POWER; + case 15: + return Position.ALARM_POWER_CUT; + case 16: + return Position.ALARM_POWER_RESTORED; + default: + return null; + } + } + return null; + } + private Object decodeLocation( Channel channel, SocketAddress remoteAddress, String sentence) { @@ -121,35 +139,33 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - position.set(Position.KEY_ALARM, parser.next()); + position.set(Position.KEY_ALARM, decodeAlarm(parser.nextInt())); position.setTime(parser.nextDateTime()); position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); - position.setCourse(parser.nextInt(0)); - position.setAltitude(parser.nextInt(0)); - - position.set(Position.KEY_ODOMETER, parser.nextLong(0)); - position.set(Position.KEY_STATUS, parser.nextHexInt(0)); - if (parser.hasNext()) { - position.set(Position.KEY_INPUT, parser.nextHexInt(0)); - } - if (parser.hasNext()) { - position.set(Position.KEY_OUTPUT, parser.nextHexInt(0)); - } + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + position.setCourse(parser.nextInt()); + position.setAltitude(parser.nextInt()); + + position.set(Position.KEY_ODOMETER, parser.nextLong()); + position.set(Position.KEY_STATUS, parser.nextHexLong()); + position.set(Position.KEY_INPUT, parser.nextHexInt()); + position.set(Position.KEY_OUTPUT, parser.nextHexInt()); position.setNetwork(new Network(CellTower.from( - parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0)))); + parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt()))); String[] adc = parser.next().split("\\|"); for (int i = 0; i < adc.length; i++) { position.set(Position.PREFIX_ADC + (i + 1), Integer.parseInt(adc[i], 16)); } - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + if (parser.hasNext()) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(parser.nextHexInt())); + } if (parser.hasNext()) { String[] sensors = parser.next().split("\\|"); diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolEncoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolEncoder.java index ff0a2e56e..a4e69b47b 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolEncoder.java @@ -18,9 +18,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.helper.Checksum; import org.traccar.model.Command; +import org.traccar.Protocol; public class FifotrackProtocolEncoder extends StringProtocolEncoder { + public FifotrackProtocolEncoder(Protocol protocol) { + super(protocol); + } + private Object formatCommand(Command command, String content) { String uniqueId = getUniqueId(command.getDeviceId()); int length = 1 + uniqueId.length() + 3 + content.length(); diff --git a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java index 86da3943e..7405fb6ef 100644 --- a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java @@ -21,6 +21,7 @@ import io.netty.handler.codec.http.HttpResponseStatus; import org.traccar.BaseHttpProtocolDecoder; import org.traccar.DeviceSession; import org.traccar.Protocol; +import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; import javax.json.Json; @@ -102,7 +103,7 @@ public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder { position.setLongitude(((JsonNumber) value).doubleValue()); return true; case "position.speed": - position.setSpeed(((JsonNumber) value).doubleValue()); + position.setSpeed(UnitsConverter.knotsFromKph(((JsonNumber) value).doubleValue())); return true; case "position.direction": position.setCourse(((JsonNumber) value).doubleValue()); diff --git a/src/main/java/org/traccar/protocol/GalileoProtocol.java b/src/main/java/org/traccar/protocol/GalileoProtocol.java index 9b7fe1a4b..a1570c9b0 100644 --- a/src/main/java/org/traccar/protocol/GalileoProtocol.java +++ b/src/main/java/org/traccar/protocol/GalileoProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ public class GalileoProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new GalileoFrameDecoder()); - pipeline.addLast(new GalileoProtocolEncoder()); + pipeline.addLast(new GalileoProtocolEncoder(GalileoProtocol.this)); pipeline.addLast(new GalileoProtocolDecoder(GalileoProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java b/src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java index 5b843324c..dfaedd695 100644 --- a/src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java @@ -318,7 +318,9 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // part number photo.writeBytes(buf, length - 1); - } else { + sendResponse(channel, 0x07, buf.readUnsignedShortLE()); + + } else if (photo != null) { DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); String uniqueId = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getUniqueId(); @@ -334,8 +336,6 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder { } - sendResponse(channel, 0x07, buf.readUnsignedShortLE()); - return position; } diff --git a/src/main/java/org/traccar/protocol/GalileoProtocolEncoder.java b/src/main/java/org/traccar/protocol/GalileoProtocolEncoder.java index 3b2145e74..cd068b251 100644 --- a/src/main/java/org/traccar/protocol/GalileoProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GalileoProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -20,11 +20,16 @@ import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; import org.traccar.helper.Checksum; import org.traccar.model.Command; +import org.traccar.Protocol; import java.nio.charset.StandardCharsets; public class GalileoProtocolEncoder extends BaseProtocolEncoder { + public GalileoProtocolEncoder(Protocol protocol) { + super(protocol); + } + private ByteBuf encodeText(String uniqueId, String text) { ByteBuf buf = Unpooled.buffer(256); diff --git a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java index 31500bae6..043839be9 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -120,8 +120,10 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_STATUS, buf.readUnsignedByte()); position.set("key", buf.readUnsignedByte()); - position.set("oil", buf.readUnsignedShort() / 10.0); - position.set(Position.KEY_POWER, buf.readUnsignedByte() + buf.readUnsignedByte() * 0.01); + + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedByte() + buf.readUnsignedByte() * 0.01); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedByte() + buf.readUnsignedByte() * 0.01); + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); return position; diff --git a/src/main/java/org/traccar/protocol/Gl200Protocol.java b/src/main/java/org/traccar/protocol/Gl200Protocol.java index c5343dae0..e2d0c6d2a 100644 --- a/src/main/java/org/traccar/protocol/Gl200Protocol.java +++ b/src/main/java/org/traccar/protocol/Gl200Protocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ public class Gl200Protocol extends BaseProtocol { protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new Gl200FrameDecoder()); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Gl200ProtocolEncoder()); + pipeline.addLast(new Gl200ProtocolEncoder(Gl200Protocol.this)); pipeline.addLast(new Gl200ProtocolDecoder(Gl200Protocol.this)); } }); @@ -44,7 +44,7 @@ public class Gl200Protocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Gl200ProtocolEncoder()); + pipeline.addLast(new Gl200ProtocolEncoder(Gl200Protocol.this)); pipeline.addLast(new Gl200ProtocolDecoder(Gl200Protocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java index 285106c67..32307446b 100644 --- a/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -17,9 +17,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class Gl200ProtocolEncoder extends StringProtocolEncoder { + public Gl200ProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 5a0ff4197..283dbeb37 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 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. @@ -119,9 +119,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .compile(); private static final Pattern PATTERN_LOCATION = new PatternBuilder() - .number("(d{1,2})?,") // hdop + .number("(d{1,2}.?d?)?,") // hdop .number("(d{1,3}.d)?,") // speed - .number("(d{1,3})?,") // course + .number("(d{1,3}.?d?)?,") // course .number("(-?d{1,5}.d)?,") // altitude .number("(-?d{1,3}.d{6})?,") // longitude .number("(-?d{1,2}.d{6})?,") // latitude @@ -184,7 +184,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .number("(d+)?,") // power .number("d{1,2},").optional() // report type .number("d{1,2},").optional() // count - .number(",").optional() // reserved + .number("d*,").optional() // reserved .number("(d+),").optional() // battery .expression("((?:") .expression(PATTERN_LOCATION.pattern()) @@ -202,6 +202,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .or() .number("(d{1,7}.d)?,").optional() // odometer .number("(d{1,3})?,") // battery + .or() + .number("(-?d),") // rssi + .number("(d{1,3}),") // battery .groupEnd() .any() .number("(dddd)(dd)(dd)") // date (yyyymmdd) @@ -514,7 +517,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } private void decodeLocation(Position position, Parser parser) { - Integer hdop = parser.nextInt(); + Double hdop = parser.nextDouble(); position.setValid(hdop == null || hdop > 0); position.set(Position.KEY_HDOP, hdop); @@ -848,6 +851,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); } position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.KEY_RSSI, parser.nextInt()); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); decodeDeviceTime(position, parser); if (ignoreFixTime) { @@ -1224,8 +1229,11 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { case "CAN": result = decodeCan(channel, remoteAddress, sentence); break; + case "CTN": case "FRI": case "GEO": + case "RTL": + case "DOG": case "STR": result = decodeFri(channel, remoteAddress, sentence); break; diff --git a/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java b/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java index 95ef18f20..76278070e 100644 --- a/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,8 @@ import org.traccar.model.Network; import org.traccar.model.Position; import java.net.SocketAddress; -import java.util.Date; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.LinkedList; import java.util.List; import java.util.regex.Pattern; @@ -45,8 +46,6 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder { .text("*GS") // header .number("d+,") // protocol version .number("(d+),") // imei - .number("(dd)(dd)(dd)") // time (hhmmss) - .number("(dd)(dd)(dd),") // date (ddmmyy) .expression("([^#]*)#?") // data .compile(); @@ -68,6 +67,7 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder { .compile(); private void decodeFragment(Position position, String fragment) { + int dataIndex = fragment.indexOf(':'); int index = 0; String[] values; @@ -76,6 +76,7 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder { } else { values = fragment.substring(dataIndex + 1).split(";"); } + switch (fragment.substring(0, dataIndex)) { case "GPS": position.setValid(values[index++].equals("A")); @@ -162,8 +163,15 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder { position.set("tagData", values[index++]); break; case "IWD": - if (index < values.length && values[index + 1].equals("0")) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, values[index + 2]); + while (index < values.length) { + int sensorIndex = Integer.parseInt(values[index++]); + int dataType = Integer.parseInt(values[index++]); + if (dataType == 0) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, values[index++]); + } else if (dataType == 1) { + index += 1; // temperature sensor serial number + position.set(Position.PREFIX_TEMP + sensorIndex, Double.parseDouble(values[index++])); + } } break; default: @@ -171,42 +179,27 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder { } } - private Object decodeData(DeviceSession deviceSession, Date time, String data) { - - List<Position> positions = new LinkedList<>(); - Position position = null; - int index = 0; - String[] fragments = data.split(","); + private Position decodePosition(DeviceSession deviceSession, String sentence) throws ParseException { - while (index < fragments.length) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); - if (fragments[index].isEmpty() || Character.isDigit(fragments[index].charAt(0))) { - - if (position != null) { - positions.add(position); - } + int index = 0; + String[] fragments = sentence.split(","); - position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.setTime(time); + position.setTime(new SimpleDateFormat("HHmmssddMMyy").parse(fragments[index++])); - if (!fragments[index++].isEmpty()) { - position.set(Position.KEY_EVENT, Integer.parseInt(fragments[index - 1])); + for (; index < fragments.length; index += 1) { + if (!fragments[index].isEmpty()) { + if (fragments[index].matches("\\p{XDigit}+")) { + position.set(Position.KEY_EVENT, Integer.parseInt(fragments[index], 16)); + } else { + decodeFragment(position, fragments[index]); } - - } else { - - decodeFragment(position, fragments[index++]); - } - } - if (position != null) { - positions.add(position); - } - - return positions; + return position; } @Override @@ -256,12 +249,11 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder { } else { - Date time = new Date(); - if (parser.hasNext(6)) { - time = parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY); + List<Position> positions = new LinkedList<>(); + for (String item : parser.next().split("\\$")) { + positions.add(decodePosition(deviceSession, item)); } - - return decodeData(deviceSession, time, parser.next()); + return positions; } } diff --git a/src/main/java/org/traccar/protocol/GotopProtocolDecoder.java b/src/main/java/org/traccar/protocol/GotopProtocolDecoder.java index 2ef975fe5..a867451aa 100644 --- a/src/main/java/org/traccar/protocol/GotopProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GotopProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -40,7 +40,7 @@ public class GotopProtocolDecoder extends BaseProtocolDecoder { .number("DATE:(dd)(dd)(dd),") // date (yyddmm) .number("TIME:(dd)(dd)(dd),") // time (hhmmss) .number("LAT:(d+.d+)([NS]),") // latitude - .number("LOT:(d+.d+)([EW]),") // longitude + .number("LO[NT]:(d+.d+)([EW]),") // longitude .text("Speed:").number("(d+.d+),") // speed .expression("([^,]+),") // status .number("(d+)?") // course diff --git a/src/main/java/org/traccar/protocol/Gps103Protocol.java b/src/main/java/org/traccar/protocol/Gps103Protocol.java index 6272a3fd1..5356387ce 100644 --- a/src/main/java/org/traccar/protocol/Gps103Protocol.java +++ b/src/main/java/org/traccar/protocol/Gps103Protocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,7 +42,7 @@ public class Gps103Protocol extends BaseProtocol { pipeline.addLast(new CharacterDelimiterFrameDecoder(2048, false, "\r\n", "\n", ";", "*")); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Gps103ProtocolEncoder()); + pipeline.addLast(new Gps103ProtocolEncoder(Gps103Protocol.this)); pipeline.addLast(new Gps103ProtocolDecoder(Gps103Protocol.this)); } }); @@ -51,7 +51,7 @@ public class Gps103Protocol extends BaseProtocol { protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Gps103ProtocolEncoder()); + pipeline.addLast(new Gps103ProtocolEncoder(Gps103Protocol.this)); pipeline.addLast(new Gps103ProtocolDecoder(Gps103Protocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java index 47ef2f333..7128823ed 100644 --- a/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class Gps103ProtocolEncoder extends StringProtocolEncoder implements StringProtocolEncoder.ValueFormatter { + public Gps103ProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override public String formatValue(String key, Object value) { diff --git a/src/main/java/org/traccar/protocol/GranitProtocol.java b/src/main/java/org/traccar/protocol/GranitProtocol.java index 6785f2a2e..244c3977b 100644 --- a/src/main/java/org/traccar/protocol/GranitProtocol.java +++ b/src/main/java/org/traccar/protocol/GranitProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,7 +28,7 @@ public class GranitProtocol extends BaseProtocol { Command.TYPE_IDENTIFICATION, Command.TYPE_REBOOT_DEVICE, Command.TYPE_POSITION_SINGLE); - setTextCommandEncoder(new GranitProtocolSmsEncoder()); + setTextCommandEncoder(new GranitProtocolSmsEncoder(this)); setSupportedTextCommands( Command.TYPE_REBOOT_DEVICE, Command.TYPE_POSITION_PERIODIC); @@ -36,7 +36,7 @@ public class GranitProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new GranitFrameDecoder()); - pipeline.addLast(new GranitProtocolEncoder()); + pipeline.addLast(new GranitProtocolEncoder(GranitProtocol.this)); pipeline.addLast(new GranitProtocolDecoder(GranitProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/GranitProtocolEncoder.java b/src/main/java/org/traccar/protocol/GranitProtocolEncoder.java index 6345ff971..66c2a4973 100644 --- a/src/main/java/org/traccar/protocol/GranitProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/GranitProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -21,9 +21,14 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class GranitProtocolEncoder extends BaseProtocolEncoder { + public GranitProtocolEncoder(Protocol protocol) { + super(protocol); + } + private ByteBuf encodeCommand(String commandString) { ByteBuf buffer = Unpooled.buffer(); buffer.writeBytes(commandString.getBytes(StandardCharsets.US_ASCII)); diff --git a/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java b/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java index 7d5518c17..7dd4b2d77 100644 --- a/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java +++ b/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,9 +18,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class GranitProtocolSmsEncoder extends StringProtocolEncoder { + public GranitProtocolSmsEncoder(Protocol protocol) { + super(protocol); + } + @Override protected String encodeCommand(Command command) { switch (command.getType()) { diff --git a/src/main/java/org/traccar/protocol/Gt06Protocol.java b/src/main/java/org/traccar/protocol/Gt06Protocol.java index 6e5435cd4..9ec8de098 100644 --- a/src/main/java/org/traccar/protocol/Gt06Protocol.java +++ b/src/main/java/org/traccar/protocol/Gt06Protocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ public class Gt06Protocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new Gt06FrameDecoder()); - pipeline.addLast(new Gt06ProtocolEncoder()); + pipeline.addLast(new Gt06ProtocolEncoder(Gt06Protocol.this)); pipeline.addLast(new Gt06ProtocolDecoder(Gt06Protocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 4665290c3..e1ff0b6b6 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -81,11 +81,13 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_X1_PHOTO_INFO = 0x35; public static final int MSG_X1_PHOTO_DATA = 0x36; public static final int MSG_WIFI_2 = 0x69; + public static final int MSG_GPS_MODULAR = 0x70; public static final int MSG_COMMAND_0 = 0x80; public static final int MSG_COMMAND_1 = 0x81; public static final int MSG_COMMAND_2 = 0x82; public static final int MSG_TIME_REQUEST = 0x8A; public static final int MSG_INFO = 0x94; + public static final int MSG_RFID = 0x9B; public static final int MSG_STRING_INFO = 0x21; public static final int MSG_GPS_2 = 0xA0; public static final int MSG_LBS_2 = 0xA1; @@ -101,6 +103,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_MULTIMEDIA = 0x21; public static final int MSG_BMS_2 = 0x40; public static final int MSG_MULTIMEDIA_2 = 0x41; + public static final int MSG_ALARM = 0x95; private static boolean isSupported(int type) { return hasGps(type) || hasLbs(type) || hasStatus(type); @@ -748,6 +751,39 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() > 0); } + } else if (type == MSG_ALARM) { + + DateBuilder dateBuilder = new DateBuilder(deviceSession.getTimeZone()) + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + + getLastLocation(position, dateBuilder.getDate()); + + short alarmType = buf.readUnsignedByte(); + + switch (alarmType) { + case 0x80: + position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); + break; + case 0x87: + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + break; + case 0x90: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 0x91: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 0x92: + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + break; + default: + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + break; + } + + position.set("alarmValue", buf.readShort()); + } else { if (dataLength > 0) { @@ -814,7 +850,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { getLastLocation(position, null); if (subType == 0x00) { - position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort() * 0.01); return position; } else if (subType == 0x05) { int flags = buf.readUnsignedByte(); @@ -824,7 +860,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } else if (subType == 0x0a) { buf.skipBytes(8); // imei buf.skipBytes(8); // imsi - position.set("iccid", ByteBufUtil.hexDump(buf.readSlice(8))); + position.set(Position.KEY_ICCID, ByteBufUtil.hexDump(buf.readSlice(8))); return position; } else if (subType == 0x0d) { if (buf.getByte(buf.readerIndex()) != '!') { @@ -942,6 +978,22 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { return position; + } else if (type == MSG_RFID) { + + getLastLocation(position, null); + + buf.readUnsignedByte(); // external device type code + buf.readUnsignedByte(); // card type + position.set( + Position.KEY_DRIVER_UNIQUE_ID, + buf.readCharSequence(buf.readableBytes() - 9, StandardCharsets.US_ASCII).toString()); + + return position; + + } else if (type == MSG_GPS_MODULAR) { + + return decodeExtendedModular(channel, buf, deviceSession, type); + } else { return decodeExtendedOther(channel, buf, deviceSession, type); @@ -951,6 +1003,84 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { return null; } + private Object decodeExtendedModular(Channel channel, ByteBuf buf, DeviceSession deviceSession, int type) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + while (buf.readableBytes() > 6) { + int moduleType = buf.readUnsignedShort(); + int moduleLength = buf.readUnsignedShort(); + switch (moduleType) { + case 0x18: + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); + break; + case 0x28: + position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); + break; + case 0x29: + position.set(Position.KEY_INDEX, buf.readUnsignedInt()); + break; + case 0x2a: + int input = buf.readUnsignedByte(); + position.set(Position.KEY_DOOR, BitUtil.to(input, 4) > 0); + position.set("tamper", BitUtil.from(input, 4) > 0); + break; + case 0x2b: + int event = buf.readUnsignedByte(); + switch (event) { + case 0x11: + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + break; + case 0x12: + position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); + break; + case 0x13: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; + case 0x14: + position.set(Position.KEY_ALARM, Position.ALARM_REMOVING); + break; + default: + break; + } + position.set(Position.KEY_EVENT, event); + break; + case 0x2e: + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + break; + case 0x33: + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.setAltitude(buf.readShort()); + + double latitude = buf.readUnsignedInt() / 60.0 / 30000.0; + double longitude = buf.readUnsignedInt() / 60.0 / 30000.0; + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + + int flags = buf.readUnsignedShort(); + position.setCourse(BitUtil.to(flags, 10)); + position.setValid(BitUtil.check(flags, 12)); + + if (!BitUtil.check(flags, 10)) { + latitude = -latitude; + } + if (BitUtil.check(flags, 11)) { + longitude = -longitude; + } + + position.setLatitude(latitude); + position.setLongitude(longitude); + break; + default: + buf.skipBytes(moduleLength); + break; + } + } + + return position; + } + private Object decodeExtendedOther(Channel channel, ByteBuf buf, DeviceSession deviceSession, int type) { Position position = null; diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java index 05560229f..9115ba10f 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,14 +21,20 @@ import org.traccar.BaseProtocolEncoder; import org.traccar.Context; import org.traccar.helper.Checksum; import org.traccar.model.Command; +import org.traccar.Protocol; import java.nio.charset.StandardCharsets; public class Gt06ProtocolEncoder extends BaseProtocolEncoder { + public Gt06ProtocolEncoder(Protocol protocol) { + super(protocol); + } + private ByteBuf encodeContent(long deviceId, String content) { - boolean language = Context.getIdentityManager().lookupAttributeBoolean(deviceId, "gt06.language", false, true); + boolean language = Context.getIdentityManager() + .lookupAttributeBoolean(deviceId, getProtocolName() + ".language", false, false, true); ByteBuf buf = Unpooled.buffer(); @@ -61,13 +67,18 @@ public class Gt06ProtocolEncoder extends BaseProtocolEncoder { protected Object encodeCommand(Command command) { boolean alternative = Context.getIdentityManager().lookupAttributeBoolean( - command.getDeviceId(), "gt06.alternative", false, true); + command.getDeviceId(), getProtocolName() + ".alternative", false, false, true); + + String password = Context.getIdentityManager() + .getDevicePassword(command.getDeviceId(), getProtocolName(), "123456"); switch (command.getType()) { case Command.TYPE_ENGINE_STOP: - return encodeContent(command.getDeviceId(), alternative ? "DYD,123456#" : "Relay,1#"); + return encodeContent(command.getDeviceId(), + alternative ? "DYD," + password + "#" : "Relay,1#"); case Command.TYPE_ENGINE_RESUME: - return encodeContent(command.getDeviceId(), alternative ? "HFYD,123456#" : "Relay,0#"); + return encodeContent(command.getDeviceId(), + alternative ? "HFYD," + password + "#" : "Relay,0#"); case Command.TYPE_CUSTOM: return encodeContent(command.getDeviceId(), command.getString(Command.KEY_DATA)); default: diff --git a/src/main/java/org/traccar/protocol/H02Protocol.java b/src/main/java/org/traccar/protocol/H02Protocol.java index 251beac5e..b897d83ad 100644 --- a/src/main/java/org/traccar/protocol/H02Protocol.java +++ b/src/main/java/org/traccar/protocol/H02Protocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ public class H02Protocol extends BaseProtocol { int messageLength = Context.getConfig().getInteger(getName() + ".messageLength"); pipeline.addLast(new H02FrameDecoder(messageLength)); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new H02ProtocolEncoder()); + pipeline.addLast(new H02ProtocolEncoder(H02Protocol.this)); pipeline.addLast(new H02ProtocolDecoder(H02Protocol.this)); } }); @@ -46,7 +46,7 @@ public class H02Protocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new StringEncoder()); - pipeline.addLast(new H02ProtocolEncoder()); + pipeline.addLast(new H02ProtocolEncoder(H02Protocol.this)); pipeline.addLast(new H02ProtocolDecoder(H02Protocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java index 22bbe4441..137689a67 100644 --- a/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java @@ -554,9 +554,18 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder { String sentence = buf.toString(StandardCharsets.US_ASCII).trim(); int typeStart = sentence.indexOf(',', sentence.indexOf(',') + 1) + 1; int typeEnd = sentence.indexOf(',', typeStart); + if (typeEnd < 0) { + typeEnd = sentence.indexOf('#', typeStart); + } if (typeEnd > 0) { String type = sentence.substring(typeStart, typeEnd); switch (type) { + case "V0": + case "HTBT": + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(sentence, remoteAddress)); + } + return null; case "NBR": return decodeLbs(sentence, channel, remoteAddress); case "LINK": diff --git a/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java b/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java index 614a07dd1..7a765332c 100644 --- a/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java @@ -1,6 +1,6 @@ /* * Copyright 2016 Gabor Somogyi (gabor.g.somogyi@gmail.com) - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -19,6 +19,7 @@ package org.traccar.protocol; import org.traccar.Context; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; import java.util.Date; @@ -26,6 +27,10 @@ public class H02ProtocolEncoder extends StringProtocolEncoder { private static final String MARKER = "HQ"; + public H02ProtocolEncoder(Protocol protocol) { + super(protocol); + } + private Object formatCommand(Date time, String uniqueId, String type, String... params) { StringBuilder result = new StringBuilder( @@ -55,7 +60,7 @@ public class H02ProtocolEncoder extends StringProtocolEncoder { case Command.TYPE_POSITION_PERIODIC: String frequency = command.getAttributes().get(Command.KEY_FREQUENCY).toString(); if (Context.getIdentityManager().lookupAttributeBoolean( - command.getDeviceId(), "h02.alternative", false, true)) { + command.getDeviceId(), getProtocolName() + ".alternative", false, false, true)) { return formatCommand(time, uniqueId, "D1", frequency); } else { return formatCommand(time, uniqueId, "S71", "22", frequency); diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java index 8a937a194..9449e2d5c 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java @@ -83,7 +83,7 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { int subtype = buf.readUnsignedShort(); int length = buf.readUnsignedShort() - 4; if (subtype == 0x0003) { - String imei = buf.readSlice(length).toString(StandardCharsets.US_ASCII); + String imei = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); if (deviceSession != null && channel != null) { ByteBuf content = Unpooled.buffer(); @@ -117,7 +117,7 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_IGNITION, BitUtil.check(status, 14)); position.set(Position.KEY_EVENT, buf.readUnsignedShort()); - String time = buf.readSlice(12).toString(StandardCharsets.US_ASCII); + String time = buf.readCharSequence(12, StandardCharsets.US_ASCII).toString(); DateBuilder dateBuilder = new DateBuilder() .setYear(Integer.parseInt(time.substring(0, 2))) @@ -138,9 +138,33 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ODOMETER, buf.readUnsignedShort() * 1000); while (buf.readableBytes() > 4) { - buf.readUnsignedShort(); // subtype + int subtype = buf.readUnsignedShort(); int length = buf.readUnsignedShort() - 4; - buf.skipBytes(length); + switch (subtype) { + case 0x0001: + position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte() - 40); + position.set(Position.KEY_RPM, buf.readUnsignedShort()); + position.set("averageSpeed", buf.readUnsignedByte()); + buf.readUnsignedShort(); // interval fuel consumption + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 0.01); + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedShort()); + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4); + buf.readUnsignedInt(); // trip id + break; + case 0x0005: + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set(Position.KEY_HDOP, buf.readUnsignedByte()); + buf.readUnsignedInt(); // run time + break; + case 0x0009: + position.set( + Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); + break; + default: + buf.skipBytes(length); + break; + } } sendResponse(channel, MSG_POSITION_RSP, index, null); diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocol.java b/src/main/java/org/traccar/protocol/HuabaoProtocol.java index 44c9f7ac7..791672b85 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocol.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ public class HuabaoProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new HuabaoFrameDecoder()); - pipeline.addLast(new HuabaoProtocolEncoder()); + pipeline.addLast(new HuabaoProtocolEncoder(HuabaoProtocol.this)); pipeline.addLast(new HuabaoProtocolDecoder(HuabaoProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 6e2e1377b..fceefa73a 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -58,7 +58,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { buf.writeShort(type); buf.writeShort(data.readableBytes()); buf.writeBytes(id); - buf.writeShort(1); // index + buf.writeShort(0); // index buf.writeBytes(data); data.release(); buf.writeByte(Checksum.xor(buf.nioBuffer(1, buf.readableBytes() - 1))); @@ -131,7 +131,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { ByteBuf response = Unpooled.buffer(); response.writeShort(index); response.writeByte(RESULT_SUCCESS); - response.writeBytes("authentication".getBytes(StandardCharsets.US_ASCII)); + response.writeBytes(ByteBufUtil.hexDump(id).getBytes(StandardCharsets.US_ASCII)); channel.writeAndFlush(new NetworkMessage( formatMessage(MSG_TERMINAL_REGISTER_RESPONSE, id, response), remoteAddress)); } @@ -197,20 +197,44 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { while (buf.readableBytes() > 2) { int subtype = buf.readUnsignedByte(); int length = buf.readUnsignedByte(); + int endIndex = buf.readerIndex() + length; switch (subtype) { case 0x01: position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100); break; + case 0x02: + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShort() * 0.1); + break; case 0x30: position.set(Position.KEY_RSSI, buf.readUnsignedByte()); break; case 0x31: position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); break; + case 0x91: + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.1); + position.set(Position.KEY_RPM, buf.readUnsignedShort()); + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte()); + position.set(Position.KEY_THROTTLE, buf.readUnsignedByte() * 100 / 255); + position.set(Position.KEY_ENGINE_LOAD, buf.readUnsignedByte() * 100 / 255); + position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte() - 40); + buf.readUnsignedShort(); + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 0.01); + buf.readUnsignedShort(); + buf.readUnsignedInt(); + buf.readUnsignedShort(); + position.set(Position.KEY_FUEL_USED, buf.readUnsignedShort() * 0.01); + break; + case 0x94: + if (length > 0) { + position.set( + Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); + } + break; default: - buf.skipBytes(length); break; } + buf.readerIndex(endIndex); } return position; @@ -233,3 +257,4 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } } + diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java index 7759790c4..40d07230d 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java @@ -21,17 +21,22 @@ import org.traccar.BaseProtocolEncoder; import org.traccar.Context; import org.traccar.helper.DataConverter; import org.traccar.model.Command; +import org.traccar.Protocol; import java.text.SimpleDateFormat; import java.util.Date; public class HuabaoProtocolEncoder extends BaseProtocolEncoder { + public HuabaoProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { boolean alternative = Context.getIdentityManager().lookupAttributeBoolean( - command.getDeviceId(), "huabao.alternative", false, true); + command.getDeviceId(), getProtocolName() + ".alternative", false, false, true); ByteBuf id = Unpooled.wrappedBuffer( DataConverter.parseHex(getUniqueId(command.getDeviceId()))); diff --git a/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java b/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java index 8c1b9b480..d76d9c92e 100644 --- a/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java @@ -44,7 +44,7 @@ public class ItsProtocolDecoder extends BaseProtocolDecoder { .expression("[^,]+,") // vendor .expression("[^,]+,") // firmware version .expression("(..),") // status - .number("(d+),") // event + .number("(d+),").optional() // event .expression("([LH]),") // history .or() .expression("([^,]+),") // type @@ -56,7 +56,7 @@ public class ItsProtocolDecoder extends BaseProtocolDecoder { .expression("[^,]*,") // vehicle registration .number("([01]),").optional() // valid .groupEnd() - .number("(dd),?(dd),?(dddd),") // date (ddmmyyyy) + .number("(dd),?(dd),?(d{2,4}),") // date (ddmmyyyy) .number("(dd),?(dd),?(dd),") // time (hhmmss) .expression("([01AV]),").optional() // valid .number("(d+.d+),([NS]),") // latitude @@ -69,16 +69,15 @@ public class ItsProtocolDecoder extends BaseProtocolDecoder { .number("(d+.?d*),") // altitude .number("d+.?d*,") // pdop .number("d+.?d*,") // hdop - .expression("[^,]*,") + .expression("[^,]*,") // operator .number("([01]),") // ignition .number("([01]),") // charging .number("(d+.?d*),") // power .number("(d+.?d*),") // battery .number("([01]),") // emergency .expression("[CO]?,") // tamper - .number("((?:x+,){5}") // main cell - .number("(?:-?x+,){12})") // other cells - .number("([01]{4}),") // inputs + .expression("(.*),") // cells + .number("([012]{4}),") // inputs .number("([01]{2}),") // outputs .groupBegin() .number("d+,") // index @@ -202,16 +201,22 @@ public class ItsProtocolDecoder extends BaseProtocolDecoder { int lac = Integer.parseInt(cells[3], 16); int cid = Integer.parseInt(cells[4], 16); Network network = new Network(CellTower.from(mcc, mnc, lac, cid, Integer.parseInt(cells[0]))); - for (int i = 0; i < 4; i++) { - lac = Integer.parseInt(cells[5 + 3 * i + 1], 16); - cid = Integer.parseInt(cells[5 + 3 * i + 2], 16); - if (lac > 0 && cid > 0) { - network.addCellTower(CellTower.from(mcc, mnc, lac, cid)); + if (!cells[5].startsWith("(")) { + for (int i = 0; i < 4; i++) { + lac = Integer.parseInt(cells[5 + 3 * i + 1], 16); + cid = Integer.parseInt(cells[5 + 3 * i + 2], 16); + if (lac > 0 && cid > 0) { + network.addCellTower(CellTower.from(mcc, mnc, lac, cid)); + } } } position.setNetwork(network); - position.set(Position.KEY_INPUT, parser.nextBinInt()); + String input = parser.next(); + if (input.charAt(input.length() - 1) == '2') { + input = input.substring(0, input.length() - 1) + '0'; + } + position.set(Position.KEY_INPUT, Integer.parseInt(input, 2)); position.set(Position.KEY_OUTPUT, parser.nextBinInt()); } diff --git a/src/main/java/org/traccar/protocol/ItsProtocolEncoder.java b/src/main/java/org/traccar/protocol/ItsProtocolEncoder.java index ebbbd87cd..f82b8e3ac 100644 --- a/src/main/java/org/traccar/protocol/ItsProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/ItsProtocolEncoder.java @@ -17,9 +17,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class ItsProtocolEncoder extends StringProtocolEncoder { + public ItsProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java b/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java index b5d060ecc..bfefb94a7 100644 --- a/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java +++ b/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java @@ -35,7 +35,7 @@ public class Jt600FrameDecoder extends BaseFrameDecoder { char type = (char) buf.getByte(buf.readerIndex()); if (type == '$') { - boolean longFormat = buf.getUnsignedByte(buf.readerIndex() + 1) == 0x75; + boolean longFormat = Jt600ProtocolDecoder.isLongFormat(buf, buf.readerIndex() + 1); int length = buf.getUnsignedShort(buf.readerIndex() + (longFormat ? 8 : 7)) + 10; if (length <= buf.readableBytes()) { return buf.readRetainedSlice(length); diff --git a/src/main/java/org/traccar/protocol/Jt600Protocol.java b/src/main/java/org/traccar/protocol/Jt600Protocol.java index 97c5fa6ce..37c82f741 100644 --- a/src/main/java/org/traccar/protocol/Jt600Protocol.java +++ b/src/main/java/org/traccar/protocol/Jt600Protocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,7 +34,7 @@ public class Jt600Protocol extends BaseProtocol { protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new Jt600FrameDecoder()); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Jt600ProtocolEncoder()); + pipeline.addLast(new Jt600ProtocolEncoder(Jt600Protocol.this)); pipeline.addLast(new Jt600ProtocolDecoder(Jt600Protocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java index 1351706e2..f456cd1ef 100644 --- a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 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. @@ -86,13 +86,17 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { } + static boolean isLongFormat(ByteBuf buf, int flagIndex) { + return buf.getUnsignedByte(flagIndex) >> 4 == 0x7; + } + private List<Position> decodeBinary(ByteBuf buf, Channel channel, SocketAddress remoteAddress) { List<Position> positions = new LinkedList<>(); buf.readByte(); // header - boolean longFormat = buf.getUnsignedByte(buf.readerIndex()) == 0x75; + boolean longFormat = isLongFormat(buf, buf.readerIndex()); String id = String.valueOf(Long.parseLong(ByteBufUtil.hexDump(buf.readSlice(5)))); DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); @@ -170,6 +174,7 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { if (protocolVersion == 0x17) { buf.readUnsignedByte(); // geofence id buf.skipBytes(3); // reserved + buf.skipBytes(buf.readableBytes() - 1); } } else if (version == 1) { diff --git a/src/main/java/org/traccar/protocol/Jt600ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Jt600ProtocolEncoder.java index fe5c63c32..199467a38 100644 --- a/src/main/java/org/traccar/protocol/Jt600ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Jt600ProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -19,9 +19,14 @@ import java.util.TimeZone; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class Jt600ProtocolEncoder extends StringProtocolEncoder { + public Jt600ProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/KhdProtocol.java b/src/main/java/org/traccar/protocol/KhdProtocol.java index cec7158ed..f77f4c311 100644 --- a/src/main/java/org/traccar/protocol/KhdProtocol.java +++ b/src/main/java/org/traccar/protocol/KhdProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ public class KhdProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new LengthFieldBasedFrameDecoder(512, 3, 2)); - pipeline.addLast(new KhdProtocolEncoder()); + pipeline.addLast(new KhdProtocolEncoder(KhdProtocol.this)); pipeline.addLast(new KhdProtocolDecoder(KhdProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java b/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java index c66129283..4a8df26c8 100644 --- a/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,12 +20,17 @@ import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; import org.traccar.helper.Checksum; import org.traccar.model.Command; +import org.traccar.Protocol; public class KhdProtocolEncoder extends BaseProtocolEncoder { public static final int MSG_CUT_OIL = 0x39; public static final int MSG_RESUME_OIL = 0x38; + public KhdProtocolEncoder(Protocol protocol) { + super(protocol); + } + private ByteBuf encodeCommand(int command, String uniqueId) { ByteBuf buf = Unpooled.buffer(); diff --git a/src/main/java/org/traccar/protocol/LaipacProtocol.java b/src/main/java/org/traccar/protocol/LaipacProtocol.java index 923b08a16..1d561dbd2 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocol.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.traccar.protocol; import io.netty.handler.codec.LineBasedFrameDecoder; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; +import org.traccar.model.Command; import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; @@ -25,12 +26,19 @@ import org.traccar.TrackerServer; public class LaipacProtocol extends BaseProtocol { public LaipacProtocol() { + + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_POSITION_SINGLE, + Command.TYPE_REBOOT_DEVICE); + addServer(new TrackerServer(false, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new LineBasedFrameDecoder(1024)); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); + pipeline.addLast(new LaipacProtocolEncoder(LaipacProtocol.this)); pipeline.addLast(new LaipacProtocolDecoder(LaipacProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 2f3cbb1b9..0c72568f3 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -17,6 +17,7 @@ package org.traccar.protocol; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; import org.traccar.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -37,29 +38,44 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { super(protocol); } - private static final Pattern PATTERN = new PatternBuilder() + public static final String DEFAULT_DEVICE_PASSWORD = "00000000"; + + private static final Pattern PATTERN_EAVSYS = new PatternBuilder() + .text("$EAVSYS,") + .expression("([^,]+),") // identifier + .expression("([0-9]+),") // iccid + .expression("(\\+?[0-9]+)?,") // sim phone number + .expression("(?:[^,]*),") // owner name + .expression("([^,]*)?") // firmware version + .text("*") + .number("(xx)") // checksum + .compile(); + + private static final Pattern PATTERN_AVRMC = new PatternBuilder() .text("$AVRMC,") .expression("([^,]+),") // identifier .number("(dd)(dd)(dd),") // time (hhmmss) .expression("([AVRPavrp]),") // validity .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") + .expression("([NS]),") // latitude hemisphere .number("(ddd)(dd.d+),") // longitude - .number("([EW]),") + .number("([EW]),") // longitude hemisphere .number("(d+.d+),") // speed .number("(d+.d+),") // course .number("(dd)(dd)(dd),") // date (ddmmyy) - .expression("([abZXTSMHFE86430]),") // event code + .expression("([0-9A-Za-z]),") // event code .expression("([\\d.]+),") // battery voltage .number("(d+),") // current mileage .number("(d),") // gps status .number("(d+),") // adc1 .number("(d+)") // adc2 - .number(",(xxxx)") // lac - .number("(xxxx),") // cid - .number("(ddd)") // mcc - .number("(ddd)") // mnc + .number(",(xxxx|x)") // lac | lac+cid = 0 + .number("(xxxx),") // cid | nothing + .number("(ddd|d)") // mcc | mcc+mnc = 0 + .number("(ddd)") // mnc | nothing .optional(4) + .expression(",([^*]*)") // anything remaining (be forward compatible) + .optional(1) .text("*") .number("(xx)") // checksum .compile(); @@ -68,6 +84,8 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { switch (event) { case "Z": return Position.ALARM_LOW_BATTERY; + case "Y": + return Position.ALARM_TOW; case "X": return Position.ALARM_GEOFENCE_ENTER; case "T": @@ -81,6 +99,8 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return Position.ALARM_GEOFENCE_EXIT; case "6": return Position.ALARM_OVERSPEED; + case "5": + return Position.ALARM_POWER_CUT; case "3": return Position.ALARM_SOS; default: @@ -88,23 +108,77 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { } } - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + private String decodeEvent(String event, Position position) { - String sentence = (String) msg; + if (event.length() == 1) { + char inputStatus = event.charAt(0); + if (inputStatus >= 'A' && inputStatus <= 'D') { + int inputStatusInt = inputStatus - 'A'; + position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); + position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); + return null; + } + } - if (sentence.startsWith("$ECHK") && channel != null) { - channel.writeAndFlush(new NetworkMessage(sentence + "\r\n", remoteAddress)); // heartbeat - return null; + return event; + } + + private void sendEventResponse( + String event, String devicePassword, Channel channel, SocketAddress remoteAddress) { + + String responseCode = null; + + switch (event) { + case "3": + responseCode = "d"; + break; + case "S": + case "T": + responseCode = "t"; + break; + case "X": + case "4": + responseCode = "x"; + break; + case "Y": + responseCode = "y"; + break; + case "Z": + responseCode = "z"; + break; + default: + break; + } + + if (responseCode != null) { + String response = "$AVCFG," + devicePassword + "," + responseCode; + response += Checksum.nmea(response) + "\r\n"; + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + + } + + private void sendAcknowledge( + String status, String event, String checksum, Channel channel, SocketAddress remoteAddress) { + + if (Character.isLowerCase(status.charAt(0))) { + String response = "$EAVACK," + event + "," + checksum; + response += Checksum.nmea(response) + "\r\n"; + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } - Parser parser = new Parser(PATTERN, sentence); + } + + protected Object decodeEavsys( + String sentence, Channel channel, SocketAddress remoteAddress) { + + Parser parser = new Parser(PATTERN_EAVSYS, sentence); if (!parser.matches()) { return null; } - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + DeviceSession deviceSession = + getDeviceSession(channel, remoteAddress, parser.next()); if (deviceSession == null) { return null; } @@ -112,6 +186,32 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); + getLastLocation(position, null); + + position.set(Position.KEY_ICCID, parser.next()); + position.set(Position.KEY_PHONE, parser.next()); + position.set(Position.KEY_VERSION_FW, parser.next()); + + return position; + } + + protected Object decodeAvrmc( + String sentence, Channel channel, SocketAddress remoteAddress) { + + Parser parser = new Parser(PATTERN_AVRMC, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = + getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + + position.setDeviceId(deviceSession.getDeviceId()); DateBuilder dateBuilder = new DateBuilder() .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); @@ -130,9 +230,9 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { String event = parser.next(); position.set(Position.KEY_ALARM, decodeAlarm(event)); - position.set(Position.KEY_EVENT, event); + position.set(Position.KEY_EVENT, decodeEvent(event, position)); position.set(Position.KEY_BATTERY, Double.parseDouble(parser.next().replaceAll("\\.", "")) * 0.001); - position.set(Position.KEY_ODOMETER, parser.nextDouble()); + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); position.set(Position.KEY_GPS, parser.nextInt()); position.set(Position.PREFIX_ADC + 1, parser.nextDouble() * 0.001); position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001); @@ -145,23 +245,39 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { position.setNetwork(new Network(CellTower.from(mcc, mnc, lac, cid))); } + parser.next(); // unused + String checksum = parser.next(); if (channel != null) { - if (event.equals("3")) { - channel.writeAndFlush(new NetworkMessage("$AVCFG,00000000,d*31\r\n", remoteAddress)); - } else if (event.equals("X") || event.equals("4")) { - channel.writeAndFlush(new NetworkMessage("$AVCFG,00000000,x*2D\r\n", remoteAddress)); - } else if (event.equals("Z")) { - channel.writeAndFlush(new NetworkMessage("$AVCFG,00000000,z*2F\r\n", remoteAddress)); - } else if (Character.isLowerCase(status.charAt(0))) { - String response = "$EAVACK," + event + "," + checksum; - response += Checksum.nmea(response) + "\r\n"; - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } + + sendAcknowledge(status, event, checksum, channel, remoteAddress); + + String devicePassword = Context.getIdentityManager() + .getDevicePassword(deviceSession.getDeviceId(), getProtocolName(), DEFAULT_DEVICE_PASSWORD); + sendEventResponse(event, devicePassword, channel, remoteAddress); } return position; } + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("$ECHK")) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(sentence + "\r\n", remoteAddress)); + } + } else if (sentence.startsWith("$EAVSYS")) { + return decodeEavsys(sentence, channel, remoteAddress); + } else if (sentence.startsWith("$AVRMC")) { + return decodeAvrmc(sentence, channel, remoteAddress); + } + + return null; + } + } diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java new file mode 100644 index 000000000..343ac9431 --- /dev/null +++ b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java @@ -0,0 +1,57 @@ +/* + * 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.StringProtocolEncoder; +import org.traccar.model.Command; +import org.traccar.helper.Checksum; +import org.traccar.Protocol; + +public class LaipacProtocolEncoder extends StringProtocolEncoder { + + public LaipacProtocolEncoder(Protocol protocol) { + super(protocol); + } + + @Override + protected String formatCommand(Command command, String format, String... keys) { + String sentence = super.formatCommand(command, "$" + format, keys); + sentence += Checksum.nmea(sentence) + "\r\n"; + return sentence; + } + + @Override + protected Object encodeCommand(Command command) { + + initDevicePassword(command, LaipacProtocolDecoder.DEFAULT_DEVICE_PASSWORD); + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return formatCommand(command, "{%s}", + Command.KEY_DATA); + case Command.TYPE_POSITION_SINGLE: + return formatCommand(command, "AVREQ,{%s},1", + Command.KEY_DEVICE_PASSWORD); + case Command.TYPE_REBOOT_DEVICE: + 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/LeafSpyProtocol.java b/src/main/java/org/traccar/protocol/LeafSpyProtocol.java new file mode 100644 index 000000000..05f63a2d7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/LeafSpyProtocol.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 Jesse Hills (jesserockz@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.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 LeafSpyProtocol extends BaseProtocol { + + public LeafSpyProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(16384)); + pipeline.addLast(new LeafSpyProtocolDecoder(LeafSpyProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java b/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java new file mode 100644 index 000000000..5b352a961 --- /dev/null +++ b/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java @@ -0,0 +1,139 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 Jesse Hills (jesserockz@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.QueryStringDecoder; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.model.Position; +import org.traccar.NetworkMessage; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.List; +import java.util.Map; + +public class LeafSpyProtocolDecoder extends BaseHttpProtocolDecoder { + + public LeafSpyProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + QueryStringDecoder decoder = new QueryStringDecoder(request.uri()); + Map<String, List<String>> params = decoder.parameters(); + if (params.isEmpty()) { + decoder = new QueryStringDecoder(request.content().toString(StandardCharsets.US_ASCII), false); + params = decoder.parameters(); + } + + Position position = new Position(getProtocolName()); + position.setValid(true); + + for (Map.Entry<String, List<String>> entry : params.entrySet()) { + for (String value : entry.getValue()) { + switch (entry.getKey()) { + case "pass": + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, value); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + break; + case "Lat": + position.setLatitude(Double.parseDouble(value)); + break; + case "Long": + position.setLongitude(Double.parseDouble(value)); + break; + case "RPM": + position.set(Position.KEY_RPM, Integer.parseInt(value)); + position.setSpeed(convertSpeed(Double.parseDouble(value) / 63, "kmh")); + break; + case "Elv": + position.setAltitude(Double.parseDouble(value)); + break; + case "SOC": + position.set(Position.KEY_BATTERY_LEVEL, Double.parseDouble(value)); + break; + case "user": + position.set(Position.KEY_DRIVER_UNIQUE_ID, value); + break; + case "ChrgMode": + position.set(Position.KEY_CHARGE, Integer.parseInt(value) != 0); + break; + case "Odo": + position.set(Position.KEY_OBD_ODOMETER, Integer.parseInt(value) * 1000); + break; + default: + try { + position.set(entry.getKey(), Double.parseDouble(value)); + } catch (NumberFormatException e) { + switch (value) { + case "true": + position.set(entry.getKey(), true); + break; + case "false": + position.set(entry.getKey(), false); + break; + default: + position.set(entry.getKey(), value); + break; + } + } + break; + } + } + } + + if (position.getFixTime() == null) { + position.setTime(new Date()); + } + + if (position.getLatitude() == 0 && position.getLongitude() == 0) { + getLastLocation(position, position.getDeviceTime()); + } + + if (position.getDeviceId() != 0) { + if (channel != null) { + HttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.OK, + Unpooled.copiedBuffer("\"status\":\"0\"", StandardCharsets.US_ASCII)); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + return position; + } else { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocol.java b/src/main/java/org/traccar/protocol/MeiligaoProtocol.java index c307c7318..e8a66e49f 100644 --- a/src/main/java/org/traccar/protocol/MeiligaoProtocol.java +++ b/src/main/java/org/traccar/protocol/MeiligaoProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,14 +36,14 @@ public class MeiligaoProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new MeiligaoFrameDecoder()); - pipeline.addLast(new MeiligaoProtocolEncoder()); + pipeline.addLast(new MeiligaoProtocolEncoder(MeiligaoProtocol.this)); pipeline.addLast(new MeiligaoProtocolDecoder(MeiligaoProtocol.this)); } }); addServer(new TrackerServer(true, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new MeiligaoProtocolEncoder()); + pipeline.addLast(new MeiligaoProtocolEncoder(MeiligaoProtocol.this)); pipeline.addLast(new MeiligaoProtocolDecoder(MeiligaoProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java b/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java index 57cbbe0fc..36e94195c 100644 --- a/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,12 +21,17 @@ import org.traccar.BaseProtocolEncoder; import org.traccar.helper.Checksum; import org.traccar.helper.DataConverter; import org.traccar.model.Command; +import org.traccar.Protocol; import java.nio.charset.StandardCharsets; import java.util.TimeZone; public class MeiligaoProtocolEncoder extends BaseProtocolEncoder { + public MeiligaoProtocolEncoder(Protocol protocol) { + super(protocol); + } + private ByteBuf encodeContent(long deviceId, int type, ByteBuf content) { ByteBuf buf = Unpooled.buffer(); diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocol.java b/src/main/java/org/traccar/protocol/MeitrackProtocol.java index c887cd3a0..7439ea611 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocol.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,7 +37,7 @@ public class MeitrackProtocol extends BaseProtocol { protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new MeitrackFrameDecoder()); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new MeitrackProtocolEncoder()); + pipeline.addLast(new MeitrackProtocolEncoder(MeitrackProtocol.this)); pipeline.addLast(new MeitrackProtocolDecoder(MeitrackProtocol.this)); } }); @@ -45,7 +45,7 @@ public class MeitrackProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new StringEncoder()); - pipeline.addLast(new MeitrackProtocolEncoder()); + pipeline.addLast(new MeitrackProtocolEncoder(MeitrackProtocol.this)); pipeline.addLast(new MeitrackProtocolDecoder(MeitrackProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java index abb6ec9d4..354e81434 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,16 @@ import org.traccar.Context; import org.traccar.StringProtocolEncoder; import org.traccar.helper.Checksum; import org.traccar.model.Command; +import org.traccar.Protocol; import java.util.Map; public class MeitrackProtocolEncoder extends StringProtocolEncoder { + public MeitrackProtocolEncoder(Protocol protocol) { + super(protocol); + } + private Object formatCommand(Command command, char dataId, String content) { String uniqueId = getUniqueId(command.getDeviceId()); int length = 1 + uniqueId.length() + 1 + content.length() + 5; @@ -38,7 +43,7 @@ public class MeitrackProtocolEncoder extends StringProtocolEncoder { Map<String, Object> attributes = command.getAttributes(); boolean alternative = Context.getIdentityManager().lookupAttributeBoolean( - command.getDeviceId(), "meitrack.alternative", false, true); + command.getDeviceId(), getProtocolName() + ".alternative", false, false, true); switch (command.getType()) { case Command.TYPE_POSITION_SINGLE: diff --git a/src/main/java/org/traccar/protocol/MictrackProtocol.java b/src/main/java/org/traccar/protocol/MictrackProtocol.java new file mode 100644 index 000000000..c8d64fd81 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MictrackProtocol.java @@ -0,0 +1,47 @@ +/* + * 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.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class MictrackProtocol extends BaseProtocol { + + public MictrackProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new MictrackProtocolDecoder(MictrackProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new MictrackProtocolDecoder(MictrackProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java new file mode 100644 index 000000000..a2fccb707 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java @@ -0,0 +1,181 @@ +/* + * 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 org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; + +import java.net.SocketAddress; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +public class MictrackProtocolDecoder extends BaseProtocolDecoder { + + public MictrackProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private Date decodeTime(String data) throws ParseException { + DateFormat dateFormat = new SimpleDateFormat("yyMMddHHmmss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + return dateFormat.parse(data); + } + + private String decodeAlarm(int event) { + switch (event) { + case 5: + return Position.ALARM_SOS; + case 8: + return Position.ALARM_LOW_BATTERY; + case 9: + return Position.ALARM_GEOFENCE_ENTER; + case 10: + return Position.ALARM_GEOFENCE_EXIT; + case 12: + return Position.ALARM_POWER_OFF; + default: + return null; + } + } + + private void decodeLocation(Position position, String data) throws ParseException { + int index = 0; + String[] values = data.split("\\+"); + + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); + + position.setValid(true); + position.setTime(decodeTime(values[index++])); + position.setLatitude(Double.parseDouble(values[index++])); + position.setLongitude(Double.parseDouble(values[index++])); + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); + position.setCourse(Integer.parseInt(values[index++])); + + int event = Integer.parseInt(values[index++]); + position.set(Position.KEY_ALARM, decodeAlarm(event)); + position.set(Position.KEY_EVENT, event); + position.set(Position.KEY_BATTERY, Integer.parseInt(values[index++]) * 0.001); + } + + private void decodeCell(Network network, String data) { + String[] values = data.split(","); + int length = values.length % 5 == 0 ? 5 : 4; + for (int i = 0; i < values.length / length; i++) { + int mnc = Integer.parseInt(values[i * length]); + int cid = Integer.parseInt(values[i * length + 1]); + int lac = Integer.parseInt(values[i * length + 2]); + int mcc = Integer.parseInt(values[i * length + 3]); + network.addCellTower(CellTower.from(mcc, mnc, lac, cid)); + } + } + + private void decodeWifi(Network network, String data) { + String[] values = data.split(","); + for (int i = 0; i < values.length / 2; i++) { + network.addWifiAccessPoint(WifiAccessPoint.from(values[i * 2], Integer.parseInt(values[i * 2 + 1]))); + } + } + + private void decodeNetwork(Position position, String data, boolean hasWifi, boolean hasCell) throws ParseException { + int index = 0; + String[] values = data.split("\\+"); + + getLastLocation(position, decodeTime(values[index++])); + + Network network = new Network(); + + if (hasWifi) { + decodeWifi(network, values[index++]); + } + + if (hasCell) { + decodeCell(network, values[index++]); + } + + position.setNetwork(network); + + int event = Integer.parseInt(values[index++]); + position.set(Position.KEY_ALARM, decodeAlarm(event)); + position.set(Position.KEY_EVENT, event); + position.set(Position.KEY_BATTERY, Integer.parseInt(values[index++]) * 0.001); + } + + private void decodeStatus(Position position, String data) throws ParseException { + int index = 0; + String[] values = data.split("\\+"); + + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); + + getLastLocation(position, decodeTime(values[index++])); + + index += 4; // fix values + + int event = Integer.parseInt(values[index++]); + position.set(Position.KEY_ALARM, decodeAlarm(event)); + position.set(Position.KEY_EVENT, event); + position.set(Position.KEY_BATTERY, Integer.parseInt(values[index++]) * 0.001); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String[] fragments = ((String) msg).split(";"); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, fragments[2]); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + switch (fragments[3]) { + case "R0": + decodeLocation(position, fragments[4]); + break; + case "R1": + decodeNetwork(position, fragments[4], true, false); + break; + case "R2": + case "R3": + decodeNetwork(position, fragments[4], false, true); + break; + case "R12": + case "R13": + decodeNetwork(position, fragments[4], true, true); + break; + case "RH": + decodeStatus(position, fragments[4]); + break; + default: + return null; + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocol.java b/src/main/java/org/traccar/protocol/MiniFinderProtocol.java index d4a154053..82534ecd8 100644 --- a/src/main/java/org/traccar/protocol/MiniFinderProtocol.java +++ b/src/main/java/org/traccar/protocol/MiniFinderProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,7 +44,7 @@ public class MiniFinderProtocol extends BaseProtocol { pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';')); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new MiniFinderProtocolEncoder()); + pipeline.addLast(new MiniFinderProtocolEncoder(MiniFinderProtocol.this)); pipeline.addLast(new MiniFinderProtocolDecoder(MiniFinderProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java b/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java index 7a3d5b226..36fb9fc2f 100644 --- a/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -19,9 +19,14 @@ import java.util.TimeZone; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class MiniFinderProtocolEncoder extends StringProtocolEncoder implements StringProtocolEncoder.ValueFormatter { + public MiniFinderProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override public String formatValue(String key, Object value) { switch (key) { diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index 51b32ae3e..b6f257d2c 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -33,6 +33,7 @@ import org.traccar.model.WifiAccessPoint; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; +import java.util.Date; public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { @@ -72,8 +73,13 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { ByteBuf buf = (ByteBuf) msg; buf.readUnsignedByte(); // header + int flags = buf.readUnsignedByte(); + buf.readUnsignedShortLE(); // length + buf.readUnsignedShortLE(); // checksum + int index = buf.readUnsignedShortLE(); + int type = buf.readUnsignedByte(); - if (BitUtil.check(buf.readUnsignedByte(), 4) && channel != null) { + if (BitUtil.check(flags, 4) && channel != null) { ByteBuf content = Unpooled.buffer(); content.writeByte(MSG_RESPONSE); @@ -82,21 +88,16 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { ByteBuf response = Unpooled.buffer(); response.writeByte(0xAB); // header - response.writeByte(0); // properties - response.writeShortLE(3); + response.writeByte(0x00); // properties + response.writeShortLE(content.readableBytes()); response.writeShortLE(Checksum.crc16(Checksum.CRC16_XMODEM, content.nioBuffer())); - response.writeShortLE(0); // index + response.writeShortLE(index); response.writeBytes(content); content.release(); channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } - buf.readUnsignedShortLE(); // length - buf.readUnsignedShortLE(); // checksum - buf.readUnsignedShortLE(); // index - int type = buf.readUnsignedByte(); - if (type == MSG_DATA) { Position position = new Position(getProtocolName()); @@ -116,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); @@ -149,6 +154,12 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { mac.substring(0, mac.length() - 1), rssi)); } break; + case 0x24: + position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); + 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 int heartRate = buf.readUnsignedByte(); diff --git a/src/main/java/org/traccar/protocol/NavisetFrameDecoder.java b/src/main/java/org/traccar/protocol/NavisetFrameDecoder.java new file mode 100644 index 000000000..e5e13b305 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NavisetFrameDecoder.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.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; +import org.traccar.helper.BitUtil; + +public class NavisetFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + int length = 2 + BitUtil.to(buf.getUnsignedShortLE(buf.readerIndex()), 12) + 2; + + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/NavisetProtocol.java b/src/main/java/org/traccar/protocol/NavisetProtocol.java new file mode 100644 index 000000000..78755ea4d --- /dev/null +++ b/src/main/java/org/traccar/protocol/NavisetProtocol.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 NavisetProtocol extends BaseProtocol { + + public NavisetProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new NavisetFrameDecoder()); + pipeline.addLast(new NavisetProtocolDecoder(NavisetProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/NavisetProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavisetProtocolDecoder.java new file mode 100644 index 000000000..10d71d76c --- /dev/null +++ b/src/main/java/org/traccar/protocol/NavisetProtocolDecoder.java @@ -0,0 +1,249 @@ +/* + * 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.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class NavisetProtocolDecoder extends BaseProtocolDecoder { + + public NavisetProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_HEADER = 0b00; + public static final int MSG_DATA = 0b01; + public static final int MSG_RESPONSE = 0b10; + public static final int MSG_RESERVE = 0b11; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(0x01); + response.writeShortLE(buf.getUnsignedShortLE(buf.writerIndex() - 2)); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + + int length = buf.readUnsignedShortLE(); + int type = BitUtil.between(length, 14, 16); + buf.readUnsignedShortLE(); // device number + + if (type == MSG_HEADER) { + + getDeviceSession(channel, remoteAddress, buf.readCharSequence(15, StandardCharsets.US_ASCII).toString()); + + } else if (type == MSG_DATA) { + + List<Position> positions = new LinkedList<>(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + int blockMask = buf.readUnsignedByte(); + + while (buf.readableBytes() > 2) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_INDEX, buf.readUnsignedShortLE()); + position.set(Position.KEY_STATUS, buf.readUnsignedByte()); + position.setValid(true); + position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); + position.setLatitude(buf.readUnsignedIntLE() * 0.000001); + position.setLongitude(buf.readUnsignedIntLE() * 0.000001); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE() * 0.1)); + + if (BitUtil.check(blockMask, 0)) { + int dataMask = buf.readUnsignedByte(); + if (BitUtil.check(dataMask, 0)) { + int satellites = buf.readUnsignedByte(); + position.setValid(BitUtil.check(satellites, 7)); + position.set(Position.KEY_SATELLITES, BitUtil.to(satellites, 7)); + } + if (BitUtil.check(dataMask, 1)) { + position.setCourse(buf.readUnsignedShortLE() * 0.1); + } + if (BitUtil.check(dataMask, 2)) { + position.setAltitude(buf.readShortLE()); + } + if (BitUtil.check(dataMask, 3)) { + position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); + } + if (BitUtil.check(dataMask, 4)) { + position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.001); + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); + } + if (BitUtil.check(dataMask, 5)) { + position.set(Position.KEY_INPUT, buf.readUnsignedByte()); + position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); + } + if (BitUtil.check(dataMask, 6)) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + } + if (BitUtil.check(dataMask, 7)) { + buf.skipBytes(6); // accelerometer + } + } + + if (BitUtil.check(blockMask, 1)) { + int dataMask = buf.readUnsignedByte(); + for (int i = 0; i < 8; i++) { + if (BitUtil.check(dataMask, i)) { + position.set(Position.PREFIX_ADC + (i + 1), buf.readUnsignedShortLE()); + } + } + } + + if (BitUtil.check(blockMask, 2)) { + int dataMask = buf.readUnsignedByte(); + if (BitUtil.check(dataMask, 0)) { + position.set(Position.KEY_DEVICE_TEMP, (int) buf.readByte()); + } + if (BitUtil.check(dataMask, 1)) { + buf.skipBytes(6); // key code + } + if (BitUtil.check(dataMask, 2)) { + position.set(Position.PREFIX_TEMP + 1, (int) buf.readByte()); + position.set(Position.PREFIX_TEMP + 2, (int) buf.readByte()); + } + if (BitUtil.check(dataMask, 3)) { + position.set(Position.PREFIX_TEMP + 3, (int) buf.readByte()); + position.set(Position.PREFIX_TEMP + 4, (int) buf.readByte()); + } + if (BitUtil.check(dataMask, 4)) { + position.set(Position.PREFIX_TEMP + 5, (int) buf.readByte()); + position.set(Position.PREFIX_TEMP + 6, (int) buf.readByte()); + position.set(Position.PREFIX_TEMP + 7, (int) buf.readByte()); + position.set(Position.PREFIX_TEMP + 8, (int) buf.readByte()); + } + if (BitUtil.check(dataMask, 5)) { + position.set(Position.KEY_HOURS, buf.readUnsignedShortLE() / 60.0); + } + if (BitUtil.check(dataMask, 6)) { + buf.readUnsignedByte(); // extra status + } + if (BitUtil.check(dataMask, 7)) { + buf.readUnsignedByte(); // geofence + } + } + + if (BitUtil.check(blockMask, 3)) { + int dataMask = buf.readUnsignedByte(); + if (BitUtil.check(dataMask, 0)) { + position.set("fuel1", buf.readUnsignedShortLE()); + } + if (BitUtil.check(dataMask, 1)) { + position.set("fuel2", buf.readUnsignedShortLE()); + } + if (BitUtil.check(dataMask, 2)) { + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShortLE()); + } + if (BitUtil.check(dataMask, 3)) { + buf.skipBytes(18); + } + if (BitUtil.check(dataMask, 4)) { + buf.readUnsignedByte(); // fuel 1 temperature + } + if (BitUtil.check(dataMask, 5)) { + buf.readUnsignedByte(); // fuel 2 temperature + } + if (BitUtil.check(dataMask, 6)) { + buf.readUnsignedShortLE(); // fuel 1 frequency + } + if (BitUtil.check(dataMask, 7)) { + buf.readUnsignedShortLE(); // fuel 2 frequency + } + } + + if (BitUtil.check(blockMask, 4)) { + int dataMask = buf.readUnsignedByte(); + if (BitUtil.check(dataMask, 0)) { + buf.readUnsignedByte(); // fuel level (percentage) + position.set(Position.KEY_RPM, buf.readUnsignedShortLE()); + position.set(Position.KEY_COOLANT_TEMP, (int) buf.readByte()); + } + if (BitUtil.check(dataMask, 1)) { + buf.readUnsignedIntLE(); // fuel consumption + } + if (BitUtil.check(dataMask, 2)) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + } + for (int i = 3; i < 8; i++) { + if (BitUtil.check(dataMask, i)) { + buf.readUnsignedShortLE(); // axle weight + } + } + } + + if (BitUtil.check(blockMask, 4)) { + int dataMask = buf.readUnsignedByte(); + if (BitUtil.check(dataMask, 0)) { + buf.readUnsignedByte(); // speed + } + if (BitUtil.check(dataMask, 1)) { + buf.readUnsignedMediumLE(); // prefix S + } + if (BitUtil.check(dataMask, 2)) { + buf.readUnsignedIntLE(); // prefix P + } + if (BitUtil.check(dataMask, 3)) { + buf.readUnsignedIntLE(); // prefix A or B + } + if (BitUtil.check(dataMask, 4)) { + buf.readUnsignedShortLE(); // prefix R + } + if (BitUtil.check(dataMask, 5)) { + buf.skipBytes(26); + } + if (BitUtil.check(dataMask, 6)) { + buf.readUnsignedIntLE(); // reserved + } + if (BitUtil.check(dataMask, 7)) { + buf.readUnsignedIntLE(); // reserved + } + } + + positions.add(position); + } + + return positions; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/NoranProtocol.java b/src/main/java/org/traccar/protocol/NoranProtocol.java index 9f3078d6d..3df364c30 100644 --- a/src/main/java/org/traccar/protocol/NoranProtocol.java +++ b/src/main/java/org/traccar/protocol/NoranProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ public class NoranProtocol extends BaseProtocol { addServer(new TrackerServer(true, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new NoranProtocolEncoder()); + pipeline.addLast(new NoranProtocolEncoder(NoranProtocol.this)); pipeline.addLast(new NoranProtocolDecoder(NoranProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/NoranProtocolEncoder.java b/src/main/java/org/traccar/protocol/NoranProtocolEncoder.java index 92826c8b2..e02a1313c 100644 --- a/src/main/java/org/traccar/protocol/NoranProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/NoranProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -19,11 +19,16 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; import java.nio.charset.StandardCharsets; public class NoranProtocolEncoder extends BaseProtocolEncoder { + public NoranProtocolEncoder(Protocol protocol) { + super(protocol); + } + private ByteBuf encodeContent(String content) { ByteBuf buf = Unpooled.buffer(12 + 56); diff --git a/src/main/java/org/traccar/protocol/PacificTrackProtocol.java b/src/main/java/org/traccar/protocol/PacificTrackProtocol.java new file mode 100644 index 000000000..08991ab64 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PacificTrackProtocol.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 PacificTrackProtocol extends BaseProtocol { + + public PacificTrackProtocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new PacificTrackProtocolDecoder(PacificTrackProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/PacificTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/PacificTrackProtocolDecoder.java new file mode 100644 index 000000000..199348c54 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PacificTrackProtocolDecoder.java @@ -0,0 +1,104 @@ +/* + * 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 PacificTrackProtocolDecoder extends BaseProtocolDecoder { + + public PacificTrackProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static int readBitExt(ByteBuf buf) { + int result = 0; + while (buf.isReadable()) { + int b = buf.readUnsignedByte(); + result <<= 7; + result += BitUtil.to(b, 7); + if (BitUtil.check(b, 7)) { + break; + } + } + return result; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readByte(); // frame start + readBitExt(buf); // frame control + readBitExt(buf); // frame length + + DeviceSession deviceSession = null; + Position position = new Position(getProtocolName()); + + while (buf.isReadable()) { + + int segmentId = readBitExt(buf); + int segmentLength = readBitExt(buf); + + switch (segmentId) { + case 0x01: + position.set(Position.KEY_EVENT, readBitExt(buf)); + break; + case 0x10: + position.setValid(BitUtil.check(buf.readUnsignedByte(), 4)); + int date = buf.readUnsignedByte(); + DateBuilder dateBuilder = new DateBuilder() + .setDate(2000 + BitUtil.from(date, 4), BitUtil.to(date, 4), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + position.setLatitude(buf.readUnsignedInt() / 1000000.0 - 90.0); + position.setLongitude(buf.readUnsignedInt() / 1000000.0 - 180.0); + int speedAndCourse = buf.readUnsignedMedium(); + position.setCourse(BitUtil.from(speedAndCourse, 12)); + position.setSpeed(UnitsConverter.knotsFromKph(BitUtil.to(speedAndCourse, 12))); + position.set(Position.KEY_INDEX, buf.readUnsignedShort()); + break; + case 0x100: + String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); + deviceSession = getDeviceSession(channel, remoteAddress, imei); + break; + default: + buf.skipBytes(segmentLength); + break; + } + } + + if (deviceSession != null) { + position.setDeviceId(deviceSession.getDeviceId()); + return position; + } else { + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/PluginProtocol.java b/src/main/java/org/traccar/protocol/PluginProtocol.java new file mode 100644 index 000000000..d5f28da9d --- /dev/null +++ b/src/main/java/org/traccar/protocol/PluginProtocol.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.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class PluginProtocol extends BaseProtocol { + + public PluginProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new PluginProtocolDecoder(PluginProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java b/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java new file mode 100644 index 000000000..106889ee0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java @@ -0,0 +1,93 @@ +/* + * 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 org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class PluginProtocolDecoder extends BaseProtocolDecoder { + + public PluginProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression("[^0-9,]*,?") + .number("([^,]+),") // device id + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(-?d+),") // altitude + .number("(-?d+),") // satellites + .number("d+,") // type + .number("(d+),") // odometer + .number("(d+),") // status + .expression("[^,]*,") + .expression("[^,]*,") + .text("0") + .groupBegin() + .text(",+,") + .number("(d+),") // event + .groupEnd("?") + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + 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.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()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/PretraceProtocol.java b/src/main/java/org/traccar/protocol/PretraceProtocol.java index f753cbdb4..9d35c1c2f 100644 --- a/src/main/java/org/traccar/protocol/PretraceProtocol.java +++ b/src/main/java/org/traccar/protocol/PretraceProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -35,7 +35,7 @@ public class PretraceProtocol extends BaseProtocol { pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ')')); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new PretraceProtocolEncoder()); + pipeline.addLast(new PretraceProtocolEncoder(PretraceProtocol.this)); pipeline.addLast(new PretraceProtocolDecoder(PretraceProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java b/src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java index 9cf951e3b..1083a252e 100644 --- a/src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,9 +19,14 @@ import org.traccar.BaseProtocolEncoder; import org.traccar.Context; import org.traccar.helper.Checksum; import org.traccar.model.Command; +import org.traccar.Protocol; public class PretraceProtocolEncoder extends BaseProtocolEncoder { + public PretraceProtocolEncoder(Protocol protocol) { + super(protocol); + } + private String formatCommand(String uniqueId, String data) { String content = uniqueId + data; return String.format("(%s^%02X)", content, Checksum.xor(content)); diff --git a/src/main/java/org/traccar/protocol/Pt215FrameDecoder.java b/src/main/java/org/traccar/protocol/Pt215FrameDecoder.java new file mode 100644 index 000000000..0b3bae914 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Pt215FrameDecoder.java @@ -0,0 +1,55 @@ +/* + * 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 new file mode 100644 index 000000000..31ddc2c7a --- /dev/null +++ b/src/main/java/org/traccar/protocol/Pt215Protocol.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 Pt215Protocol extends BaseProtocol { + + public Pt215Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new Pt215FrameDecoder()); + pipeline.addLast(new Pt215ProtocolDecoder(Pt215Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Pt215ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Pt215ProtocolDecoder.java new file mode 100644 index 000000000..48ce7dede --- /dev/null +++ b/src/main/java/org/traccar/protocol/Pt215ProtocolDecoder.java @@ -0,0 +1,118 @@ +/* + * 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.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; + +public class Pt215ProtocolDecoder extends BaseProtocolDecoder { + + public Pt215ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_LOGIN = 0x01; + public static final int MSG_HEARTBEAT = 0x08; + public static final int MSG_GPS_REALTIME = 0x10; + public static final int MSG_GPS_OFFLINE = 0x11; + public static final int MSG_STATUS = 0x13; + + private void sendResponse( + Channel channel, SocketAddress remoteAddress, int type, ByteBuf content) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte('X'); + response.writeByte('X'); + response.writeByte(content != null ? 1 + content.readableBytes() : 1); + response.writeByte(type); + if (content != null) { + response.writeBytes(content); + content.release(); + } + response.writeByte('\r'); + response.writeByte('\n'); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + buf.readUnsignedByte(); // length + int type = buf.readUnsignedByte(); + + if (type == MSG_LOGIN) { + + getDeviceSession(channel, remoteAddress, ByteBufUtil.hexDump(buf.readSlice(8)).substring(1)); + sendResponse(channel, remoteAddress, type, null); + + } else if (type == MSG_GPS_OFFLINE || type == MSG_GPS_REALTIME) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + sendResponse(channel, remoteAddress, type, buf.retainedSlice(buf.readerIndex(), 6)); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + double latitude = buf.readUnsignedInt() / 60.0 / 30000.0; + double longitude = buf.readUnsignedInt() / 60.0 / 30000.0; + + int flags = buf.readUnsignedShort(); + position.setCourse(BitUtil.to(flags, 10)); + position.setValid(BitUtil.check(flags, 12)); + + if (!BitUtil.check(flags, 10)) { + latitude = -latitude; + } + if (BitUtil.check(flags, 11)) { + longitude = -longitude; + } + + position.setLatitude(latitude); + position.setLongitude(longitude); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Pt502Protocol.java b/src/main/java/org/traccar/protocol/Pt502Protocol.java index 5afb9451d..56444fb42 100644 --- a/src/main/java/org/traccar/protocol/Pt502Protocol.java +++ b/src/main/java/org/traccar/protocol/Pt502Protocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ public class Pt502Protocol extends BaseProtocol { protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new Pt502FrameDecoder()); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Pt502ProtocolEncoder()); + pipeline.addLast(new Pt502ProtocolEncoder(Pt502Protocol.this)); pipeline.addLast(new Pt502ProtocolDecoder(Pt502Protocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java index ed18208cc..ba08b16ae 100644 --- a/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -19,9 +19,14 @@ import java.util.TimeZone; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class Pt502ProtocolEncoder extends StringProtocolEncoder implements StringProtocolEncoder.ValueFormatter { + public Pt502ProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override public String formatValue(String key, Object value) { if (key.equals(Command.KEY_TIMEZONE)) { diff --git a/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java b/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java new file mode 100644 index 000000000..c9db10610 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.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.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class RaceDynamicsProtocol extends BaseProtocol { + + public RaceDynamicsProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1500)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new RaceDynamicsProtocolDecoder(RaceDynamicsProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/RaceDynamicsProtocolDecoder.java b/src/main/java/org/traccar/protocol/RaceDynamicsProtocolDecoder.java new file mode 100644 index 000000000..f441bf8ed --- /dev/null +++ b/src/main/java/org/traccar/protocol/RaceDynamicsProtocolDecoder.java @@ -0,0 +1,171 @@ +/* + * 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 org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; + +public class RaceDynamicsProtocolDecoder extends BaseProtocolDecoder { + + public RaceDynamicsProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_LOGIN = 12; + public static final int MSG_LOCATION = 15; + + private static final Pattern PATTERN_LOGIN = new PatternBuilder() + .text("$GPRMC,") + .number("d+,") // type + .number("d{6},") // date + .number("d{6},") // time + .number("(d{15}),") + .compile(); + + private static final Pattern PATTERN_LOCATION = new PatternBuilder() + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+),") // speed + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(-?d+),") // altitude + .number("(d+),") // satellites + .number("([01]),") // ignition + .number("(d+),") // index + .text("%,") + .number("([^,]+),") // ibutton + .number("d+,") // acceleration + .number("d+,") // deceleration + .number("[01],") // cruise control + .number("[01],") // seat belt + .number("[01],") // wrong ibutton + .number("(d+),") // power + .number("[01],") // power status + .number("(d+),") // battery + .number("([01]),") // panic + .number("d+,") + .number("d+,") + .number("(d),") // overspeed + .number("d+,") // speed limit + .number("d+,") // tachometer + .number("d+,d+,d+,") // aux + .number("d+,") // geofence id + .number("d+,") // road speed type + .number("d+,") // ibutton count + .number("(d),") // overdriver alert + .any() + .compile(); + + private String imei; + + private void sendResponse(Channel channel, SocketAddress remoteAddress, int type) { + if (channel != null) { + String response = String.format( + "$GPRMC,%1$d,%2$td%2$tm%2$ty,%2$tH%2$tM%2$tS,%3$s,\r\n", type, new Date(), imei); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + int type = Integer.parseInt(sentence.substring(7, 9)); + + if (type == MSG_LOGIN) { + + Parser parser = new Parser(PATTERN_LOGIN, sentence); + if (parser.matches()) { + imei = parser.next(); + getDeviceSession(channel, remoteAddress, imei); + sendResponse(channel, remoteAddress, type); + } + + } else if (type == MSG_LOCATION) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + List<Position> positions = new LinkedList<>(); + + for (String data : sentence.substring(17, sentence.length() - 3).split(",#,#,")) { + Parser parser = new Parser(PATTERN_LOCATION, data); + if (parser.matches()) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble()); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + position.setAltitude(parser.nextInt()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_IGNITION, parser.nextInt() == 1); + position.set(Position.KEY_INDEX, parser.nextInt()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + position.set(Position.KEY_POWER, parser.nextInt() * 0.01); + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.01); + position.set(Position.KEY_ALARM, parser.nextInt() > 0 ? Position.ALARM_SOS : null); + position.set(Position.KEY_ALARM, parser.nextInt() > 0 ? Position.ALARM_OVERSPEED : null); + + int overDriver = parser.nextInt(); + if (overDriver > 0) { + position.set("overDriver", overDriver); + } + + positions.add(position); + + } + } + + sendResponse(channel, remoteAddress, type); + + return positions; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/RstProtocol.java b/src/main/java/org/traccar/protocol/RstProtocol.java new file mode 100644 index 000000000..10d11d493 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RstProtocol.java @@ -0,0 +1,37 @@ +/* + * 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.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class RstProtocol extends BaseProtocol { + + public RstProtocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new RstProtocolDecoder(RstProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java new file mode 100644 index 000000000..071200d6d --- /dev/null +++ b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java @@ -0,0 +1,128 @@ +/* + * 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 org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class RstProtocolDecoder extends BaseProtocolDecoder { + + public RstProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("RST;") + .expression("([AL]);") // archive + .expression("([^,]+);") // model + .expression("(.{5});") // firmware + .number("(d{9});") // serial number + .number("(d+);") // index + .number("(d+);") // type + .number("(dd)-(dd)-(dddd) ") // event date + .number("(dd):(dd):(dd);") // event time + .number("(dd)-(dd)-(dddd) ") // fix date + .number("(dd):(dd):(dd);") // fix time + .number("(-?d+.d+);") // latitude + .number("(-?d+.d+);") // longitude + .number("(d+);") // speed + .number("(d+);") // course + .number("(-?d+);") // altitude + .number("([01]);") // valid + .number("(d+);") // satellites + .number("(d+);") // hdop + .number("(xx);") // inputs 1 + .number("(xx);") // inputs 2 + .number("(xx);") // inputs 3 + .number("(xx);") // outputs 1 + .number("(xx);") // outputs 2 + .number("(d+.d+);") // power + .number("(d+.d+);") // battery + .number("(d+);") // odometer + .number("(d+);") // rssi + .number("(xx);") // temperature + .number("x{4};") // sensors + .number("(xx);") // status 1 + .number("(xx);") // status 2 + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + String archive = parser.next(); + String model = parser.next(); + String firmware = parser.next(); + String serial = parser.next(); + int index = parser.nextInt(); + int type = parser.nextInt(); + + if (channel != null && archive.equals("A")) { + String response = "RST;A;" + model + ";" + firmware + ";" + serial + ";" + index + ";" + type + ";FIM;"; + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, serial); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setDeviceTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + position.setFixTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + position.setCourse(parser.nextInt()); + position.setAltitude(parser.nextInt()); + position.setValid(parser.nextInt() > 0); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_HDOP, parser.nextInt()); + position.set(Position.PREFIX_IN + 1, parser.nextHexInt()); + position.set(Position.PREFIX_IN + 2, parser.nextHexInt()); + position.set(Position.PREFIX_IN + 3, parser.nextHexInt()); + position.set(Position.PREFIX_OUT + 1, parser.nextHexInt()); + position.set(Position.PREFIX_OUT + 2, parser.nextHexInt()); + position.set(Position.KEY_POWER, parser.nextDouble()); + position.set(Position.KEY_BATTERY, parser.nextDouble()); + 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()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocol.java b/src/main/java/org/traccar/protocol/RuptelaProtocol.java index a574293cd..b8f72336b 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocol.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,7 +37,7 @@ public class RuptelaProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 2, 2, 0)); - pipeline.addLast(new RuptelaProtocolEncoder()); + pipeline.addLast(new RuptelaProtocolEncoder(RuptelaProtocol.this)); pipeline.addLast(new RuptelaProtocolDecoder(RuptelaProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java index 96d0da5a7..51967403d 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java @@ -20,11 +20,16 @@ import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; import org.traccar.helper.Checksum; import org.traccar.model.Command; +import org.traccar.Protocol; import java.nio.charset.StandardCharsets; public class RuptelaProtocolEncoder extends BaseProtocolEncoder { + public RuptelaProtocolEncoder(Protocol protocol) { + super(protocol); + } + private ByteBuf encodeContent(int type, ByteBuf content) { ByteBuf buf = Unpooled.buffer(); diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java index d7836b35d..f9c79fb5b 100644 --- a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -16,6 +16,7 @@ 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 io.netty.handler.codec.http.FullHttpRequest; @@ -25,7 +26,9 @@ import org.traccar.DeviceSession; import org.traccar.Protocol; import org.traccar.helper.DataConverter; import org.traccar.helper.UnitsConverter; +import org.traccar.model.Network; import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; import javax.json.Json; import javax.json.JsonObject; @@ -46,8 +49,11 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { FullHttpRequest request = (FullHttpRequest) msg; - JsonObject json = Json.createReader(new StringReader(URLDecoder.decode( - request.content().toString(StandardCharsets.UTF_8).split("=")[0], "UTF-8"))).readObject(); + String content = request.content().toString(StandardCharsets.UTF_8); + if (!content.startsWith("{")) { + content = URLDecoder.decode(content.split("=")[0], "UTF-8"); + } + JsonObject json = Json.createReader(new StringReader(content)).readObject(); DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, json.getString("device")); if (deviceSession == null) { @@ -58,32 +64,101 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - position.setTime(new Date(json.getInt("time") * 1000L)); - - ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(json.getString("data"))); - try { - int type = buf.readUnsignedByte() >> 4; - if (type == 0) { - - position.setValid(true); - position.setLatitude(buf.readIntLE() * 0.0000001); - position.setLongitude(buf.readIntLE() * 0.0000001); - position.setCourse(buf.readUnsignedByte() * 2); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - - position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.025); - - } else { - - getLastLocation(position, position.getDeviceTime()); + if (json.containsKey("time")) { + position.setTime(new Date(json.getInt("time") * 1000L)); + } else { + position.setTime(new Date()); + } + if (json.containsKey("location")) { + + JsonObject location = json.getJsonObject("location"); + + position.setValid(true); + position.setLatitude(location.getJsonNumber("lat").doubleValue()); + position.setLongitude(location.getJsonNumber("lng").doubleValue()); + + } else { + + String data = json.getString(json.containsKey("data") ? "data" : "payload"); + ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(data)); + try { + int event = buf.readUnsignedByte(); + if (event >> 4 == 0) { + + position.setValid(true); + position.setLatitude(buf.readIntLE() * 0.0000001); + position.setLongitude(buf.readIntLE() * 0.0000001); + position.setCourse(buf.readUnsignedByte() * 2); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + + position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.025); + + } else { + + position.set(Position.KEY_EVENT, event); + if (event == 0x22 || event == 0x62) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } + + while (buf.isReadable()) { + int type = buf.readUnsignedByte(); + switch (type) { + case 0x01: + position.setValid(true); + position.setLatitude(buf.readMedium()); + position.setLongitude(buf.readMedium()); + break; + case 0x02: + position.setValid(true); + position.setLatitude(buf.readFloat()); + position.setLongitude(buf.readFloat()); + break; + case 0x03: + position.set(Position.PREFIX_TEMP + 1, buf.readByte() * 0.5); + break; + case 0x04: + position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.1); + break; + case 0x05: + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + break; + case 0x06: + String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); + position.setNetwork(new Network(WifiAccessPoint.from( + mac.substring(0, mac.length() - 1), buf.readUnsignedByte()))); + break; + case 0x07: + buf.skipBytes(10); // wifi extended + break; + case 0x08: + buf.skipBytes(6); // accelerometer + break; + case 0x09: + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + break; + default: + buf.readUnsignedByte(); // fence number + break; + } + } + + } + } finally { + buf.release(); } - } finally { - buf.release(); } - position.set(Position.KEY_RSSI, json.getJsonNumber("rssi").doubleValue()); - position.set(Position.KEY_INDEX, json.getInt("seqNumber")); + if (position.getLatitude() == 0 && position.getLongitude() == 0) { + getLastLocation(position, position.getDeviceTime()); + } + + if (json.containsKey("rssi")) { + position.set(Position.KEY_RSSI, json.getJsonNumber("rssi").doubleValue()); + } + if (json.containsKey("seqNumber")) { + position.set(Position.KEY_INDEX, json.getInt("seqNumber")); + } sendResponse(channel, HttpResponseStatus.OK); return position; diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java index ed5f81c1c..bad6f03a9 100644 --- a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -34,21 +34,7 @@ import java.util.regex.Pattern; public class StarLinkProtocolDecoder extends BaseProtocolDecoder { - private String[] dataTags; - private DateFormat dateFormat; - - public StarLinkProtocolDecoder(Protocol protocol) { - super(protocol); - - String format = Context.getConfig().getString( - getProtocolName() + ".format", "#EDT#,#EID#,#PDT#,#LAT#,#LONG#,#SPD#,#HEAD#,#ODO#," - + "#IN1#,#IN2#,#IN3#,#IN4#,#OUT1#,#OUT2#,#OUT3#,#OUT4#,#LAC#,#CID#,#VIN#,#VBAT#,#DEST#,#IGN#,#ENG#"); - dataTags = format.split(","); - - dateFormat = new SimpleDateFormat( - Context.getConfig().getString(getProtocolName() + ".dateFormat", "yyMMddHHmmss")); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - } + public static final int MSG_EVENT_REPORT = 6; private static final Pattern PATTERN = new PatternBuilder() .expression(".") // protocol head @@ -61,7 +47,27 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder { .number("xx") // checksum .compile(); - public static final int MSG_EVENT_REPORT = 6; + private String[] dataTags; + private DateFormat dateFormat; + + public StarLinkProtocolDecoder(Protocol protocol) { + super(protocol); + + setFormat(Context.getConfig().getString( + getProtocolName() + ".format", "#EDT#,#EID#,#PDT#,#LAT#,#LONG#,#SPD#,#HEAD#,#ODO#," + + "#IN1#,#IN2#,#IN3#,#IN4#,#OUT1#,#OUT2#,#OUT3#,#OUT4#,#LAC#,#CID#,#VIN#,#VBAT#,#DEST#,#IGN#,#ENG#")); + + setDateFormat(Context.getConfig().getString(getProtocolName() + ".dateFormat", "yyMMddHHmmss")); + } + + public void setFormat(String format) { + dataTags = format.split(","); + } + + public void setDateFormat(String dateFormat) { + this.dateFormat = new SimpleDateFormat(dateFormat); + this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + } private double parseCoordinate(String value) { int minutesIndex = value.indexOf('.') - 2; @@ -151,31 +157,19 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder { position.setCourse(Integer.parseInt(data[i])); break; case "#ODO#": - position.set(Position.KEY_ODOMETER, Long.parseLong(data[i]) * 1000); + position.set(Position.KEY_ODOMETER, (long) (Double.parseDouble(data[i]) * 1000)); break; case "#IN1#": - position.set(Position.PREFIX_IN + 1, Integer.parseInt(data[i])); - break; case "#IN2#": - position.set(Position.PREFIX_IN + 2, Integer.parseInt(data[i])); - break; case "#IN3#": - position.set(Position.PREFIX_IN + 3, Integer.parseInt(data[i])); - break; case "#IN4#": - position.set(Position.PREFIX_IN + 4, Integer.parseInt(data[i])); + position.set(Position.PREFIX_IN + dataTags[i].charAt(3), Integer.parseInt(data[i])); break; case "#OUT1#": - position.set(Position.PREFIX_OUT + 1, Integer.parseInt(data[i])); - break; case "#OUT2#": - position.set(Position.PREFIX_OUT + 2, Integer.parseInt(data[i])); - break; case "#OUT3#": - position.set(Position.PREFIX_OUT + 3, Integer.parseInt(data[i])); - break; case "#OUT4#": - position.set(Position.PREFIX_OUT + 4, Integer.parseInt(data[i])); + position.set(Position.PREFIX_OUT + dataTags[i].charAt(3), Integer.parseInt(data[i])); break; case "#LAC#": if (!data[i].isEmpty()) { diff --git a/src/main/java/org/traccar/protocol/SuntechProtocol.java b/src/main/java/org/traccar/protocol/SuntechProtocol.java index 48d6e81c1..7e2c20e6f 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocol.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocol.java @@ -39,7 +39,7 @@ public class SuntechProtocol extends BaseProtocol { pipeline.addLast(new SuntechFrameDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new SuntechProtocolEncoder()); + 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 bd485ca70..e40096a77 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java @@ -50,7 +50,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { public int getProtocolType(long deviceId) { return Context.getIdentityManager().lookupAttributeInteger( - deviceId, getProtocolName() + ".protocolType", protocolType, true); + deviceId, getProtocolName() + ".protocolType", protocolType, false, true); } public void setHbm(boolean hbm) { @@ -59,7 +59,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { public boolean isHbm(long deviceId) { return Context.getIdentityManager().lookupAttributeBoolean( - deviceId, getProtocolName() + ".hbm", hbm, true); + deviceId, getProtocolName() + ".hbm", hbm, false, true); } public void setIncludeAdc(boolean includeAdc) { @@ -68,7 +68,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { public boolean isIncludeAdc(long deviceId) { return Context.getIdentityManager().lookupAttributeBoolean( - deviceId, getProtocolName() + ".includeAdc", includeAdc, true); + deviceId, getProtocolName() + ".includeAdc", includeAdc, false, true); } public void setIncludeRpm(boolean includeRpm) { @@ -77,7 +77,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { public boolean isIncludeRpm(long deviceId) { return Context.getIdentityManager().lookupAttributeBoolean( - deviceId, getProtocolName() + ".includeRpm", includeRpm, true); + deviceId, getProtocolName() + ".includeRpm", includeRpm, false, true); } public void setIncludeTemp(boolean includeTemp) { @@ -86,7 +86,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { public boolean isIncludeTemp(long deviceId) { return Context.getIdentityManager().lookupAttributeBoolean( - deviceId, getProtocolName() + ".includeTemp", includeTemp, true); + deviceId, getProtocolName() + ".includeTemp", includeTemp, false, true); } private Position decode9( @@ -326,12 +326,40 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { case "UEX": int remaining = Integer.parseInt(values[index++]); while (remaining > 0) { - String value = values[index++]; - String[] pair = value.split("="); - if (pair.length >= 2) { - position.set(pair[0].toLowerCase(), pair[1].trim()); + String attribute = values[index++]; + if (attribute.startsWith("CabAVL")) { + String[] data = attribute.split(","); + double fuel1 = Double.parseDouble(data[2]); + if (fuel1 > 0) { + position.set("fuel1", fuel1); + } + double fuel2 = Double.parseDouble(data[3]); + if (fuel2 > 0) { + position.set("fuel2", fuel2); + } + } else { + String[] pair = attribute.split("="); + if (pair.length >= 2) { + String value = pair[1].trim(); + if (value.contains(".")) { + value = value.substring(0, value.indexOf('.')); + } + switch (pair[0].charAt(0)) { + case 't': + position.set(Position.PREFIX_TEMP + pair[0].charAt(2), Integer.parseInt(value, 16)); + break; + case 'N': + position.set("fuel" + pair[0].charAt(2), Integer.parseInt(value, 16)); + break; + case 'Q': + position.set("drivingQuality", Integer.parseInt(value, 16)); + break; + default: + break; + } + } } - remaining -= value.length() + 1; + remaining -= attribute.length() + 1; } break; default: @@ -393,7 +421,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { String type = values[index++]; - if (!type.equals("STT")) { + if (!type.equals("STT") && !type.equals("ALT")) { return null; } diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java index 90fa4aa39..6dae42ad5 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class SuntechProtocolEncoder extends StringProtocolEncoder { + public SuntechProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/SviasProtocol.java b/src/main/java/org/traccar/protocol/SviasProtocol.java index f01f28389..accfa173f 100644 --- a/src/main/java/org/traccar/protocol/SviasProtocol.java +++ b/src/main/java/org/traccar/protocol/SviasProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 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. @@ -42,7 +42,7 @@ public class SviasProtocol extends BaseProtocol { pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "]")); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new SviasProtocolEncoder()); + pipeline.addLast(new SviasProtocolEncoder(SviasProtocol.this)); pipeline.addLast(new SviasProtocolDecoder(SviasProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java b/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java index 8bfbef119..2607d7bd1 100644 --- a/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2019 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,9 +18,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class SviasProtocolEncoder extends StringProtocolEncoder { + public SviasProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { switch (command.getType()) { diff --git a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java index ba231a635..b75addfae 100644 --- a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java @@ -96,6 +96,19 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { .any() .compile(); + private static final Pattern PATTERN_GPIOP = new PatternBuilder() + .text("$GPIOP,") + .number("[01]{8},") // inputs + .number("[01]{8},") // outputs + .number("d+.d+,") // adc 1 + .number("d+.d+,") // adc 2 + .number("d+.d+,") // adc 3 + .number("d+.d+,") // adc 4 + .number("(d+.d+),") // power + .number("(d+.d+)") // battery + .any() + .compile(); + private Position position = null; private Position decodeGprmc( @@ -103,7 +116,7 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { if (deviceSession != null && channel != null && !(channel instanceof DatagramChannel) && Context.getIdentityManager().lookupAttributeBoolean( - deviceSession.getDeviceId(), getProtocolName() + ".ack", false, true)) { + deviceSession.getDeviceId(), getProtocolName() + ".ack", false, false, true)) { channel.writeAndFlush(new NetworkMessage("OK1\r\n", remoteAddress)); } @@ -225,6 +238,24 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { return position; } + private Position decodeGpiop(DeviceSession deviceSession, String sentence) { + + Parser parser = new Parser(PATTERN_GPIOP, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_POWER, parser.nextDouble()); + position.set(Position.KEY_BATTERY, parser.nextDouble()); + + return position; + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -275,6 +306,8 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { return decodeGprma(deviceSession, sentence); } else if (sentence.startsWith("$TRCCR") && deviceSession != null) { return decodeTrccr(deviceSession, sentence); + } else if (sentence.startsWith("$GPIOP")) { + return decodeGpiop(deviceSession, sentence); } return null; diff --git a/src/main/java/org/traccar/protocol/T800xProtocol.java b/src/main/java/org/traccar/protocol/T800xProtocol.java index 85749d0cf..8b91265cb 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocol.java +++ b/src/main/java/org/traccar/protocol/T800xProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ public class T800xProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2, -5, 0)); - pipeline.addLast(new T800xProtocolEncoder()); + pipeline.addLast(new T800xProtocolEncoder(T800xProtocol.this)); pipeline.addLast(new T800xProtocolDecoder(T800xProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java index 96fb7f96a..9b146ec90 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java @@ -31,19 +31,30 @@ import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; +import java.math.BigInteger; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; +import java.util.Date; public class T800xProtocolDecoder extends BaseProtocolDecoder { + private short header = DEFAULT_HEADER; + + public short getHeader() { + return header; + } + public T800xProtocolDecoder(Protocol protocol) { super(protocol); } + public static final short DEFAULT_HEADER = 0x2323; + public static final int MSG_LOGIN = 0x01; public static final int MSG_GPS = 0x02; public static final int MSG_HEARTBEAT = 0x03; public static final int MSG_ALARM = 0x04; + public static final int MSG_NETWORK = 0x05; public static final int MSG_COMMAND = 0x81; private void sendResponse(Channel channel, short header, int type, int index, ByteBuf imei, int alarm) { @@ -91,13 +102,24 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { } } + private Date readDate(ByteBuf buf) { + return new DateBuilder() + .setYear(BcdUtil.readInteger(buf, 2)) + .setMonth(BcdUtil.readInteger(buf, 2)) + .setDay(BcdUtil.readInteger(buf, 2)) + .setHour(BcdUtil.readInteger(buf, 2)) + .setMinute(BcdUtil.readInteger(buf, 2)) + .setSecond(BcdUtil.readInteger(buf, 2)) + .getDate(); + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; - short header = buf.readShort(); + header = buf.readShort(); int type = buf.readUnsignedByte(); buf.readUnsignedShort(); // length int index = buf.readUnsignedShort(); @@ -109,9 +131,32 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { return null; } + if (type != MSG_GPS && type != MSG_ALARM) { + sendResponse(channel, header, type, index, imei, 0); + } + if (type == MSG_GPS || type == MSG_ALARM) { - return decodePosition(channel, deviceSession, buf, header, type, index, imei); + return decodePosition(channel, deviceSession, buf, type, index, imei); + + } else if (type == MSG_NETWORK) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, readDate(buf)); + + position.set(Position.KEY_OPERATOR, buf.readCharSequence( + buf.readUnsignedByte(), StandardCharsets.UTF_16LE).toString()); + position.set("networkTechnology", buf.readCharSequence( + buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString()); + position.set("networkBand", buf.readCharSequence( + buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString()); + buf.readCharSequence(buf.readUnsignedByte(), StandardCharsets.US_ASCII); // imsi + position.set(Position.KEY_ICCID, buf.readCharSequence( + buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString()); + + return position; } else if (type == MSG_COMMAND) { @@ -124,77 +169,77 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_RESULT, buf.toString(StandardCharsets.UTF_16LE)); - sendResponse(channel, header, type, index, imei, 0); - return position; } - sendResponse(channel, header, type, index, imei, 0); - return null; } private Position decodePosition( Channel channel, DeviceSession deviceSession, - ByteBuf buf, short header, int type, int index, ByteBuf imei) { + ByteBuf buf, int type, int index, ByteBuf imei) { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); position.set(Position.KEY_INDEX, index); - buf.readUnsignedShort(); // acc on interval - buf.readUnsignedShort(); // acc off interval - buf.readUnsignedByte(); // angle compensation - buf.readUnsignedShort(); // distance compensation + if (header != 0x2727) { + + buf.readUnsignedShort(); // acc on interval + buf.readUnsignedShort(); // acc off interval + buf.readUnsignedByte(); // angle compensation + buf.readUnsignedShort(); // distance compensation - position.set(Position.KEY_RSSI, BitUtil.to(buf.readUnsignedShort(), 7)); + position.set(Position.KEY_RSSI, BitUtil.to(buf.readUnsignedShort(), 7)); + + } int status = buf.readUnsignedByte(); position.set(Position.KEY_SATELLITES, BitUtil.to(status, 5)); - buf.readUnsignedByte(); // gsensor manager status - buf.readUnsignedByte(); // other flags - buf.readUnsignedByte(); // heartbeat - buf.readUnsignedByte(); // relay status - buf.readUnsignedShort(); // drag alarm setting - - int io = buf.readUnsignedShort(); - position.set(Position.KEY_IGNITION, BitUtil.check(io, 14)); - position.set("ac", BitUtil.check(io, 13)); - for (int i = 0; i <= 2; i++) { - position.set(Position.PREFIX_OUT + (i + 1), BitUtil.check(io, 7 + i)); - } + if (header != 0x2727) { - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); + buf.readUnsignedByte(); // gsensor manager status + buf.readUnsignedByte(); // other flags + buf.readUnsignedByte(); // heartbeat + buf.readUnsignedByte(); // relay status + buf.readUnsignedShort(); // drag alarm setting + + int io = buf.readUnsignedShort(); + position.set(Position.KEY_IGNITION, BitUtil.check(io, 14)); + position.set("ac", BitUtil.check(io, 13)); + for (int i = 0; i <= 2; i++) { + position.set(Position.PREFIX_OUT + (i + 1), BitUtil.check(io, 7 + i)); + } + + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); + + } int alarm = buf.readUnsignedByte(); position.set(Position.KEY_ALARM, decodeAlarm(alarm)); - buf.readUnsignedByte(); // reserved + if (header != 0x2727) { - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + buf.readUnsignedByte(); // reserved - int battery = BcdUtil.readInteger(buf, 2); - if (battery == 0) { - battery = 100; - } - position.set(Position.KEY_BATTERY, battery); + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); - DateBuilder dateBuilder = new DateBuilder() - .setYear(BcdUtil.readInteger(buf, 2)) - .setMonth(BcdUtil.readInteger(buf, 2)) - .setDay(BcdUtil.readInteger(buf, 2)) - .setHour(BcdUtil.readInteger(buf, 2)) - .setMinute(BcdUtil.readInteger(buf, 2)) - .setSecond(BcdUtil.readInteger(buf, 2)); + int battery = BcdUtil.readInteger(buf, 2); + if (battery == 0) { + battery = 100; + } + position.set(Position.KEY_BATTERY, battery); + + } if (BitUtil.check(status, 6)) { position.setValid(!BitUtil.check(status, 7)); - position.setTime(dateBuilder.getDate()); + position.setTime(readDate(buf)); position.setAltitude(buf.readFloatLE()); position.setLongitude(buf.readFloatLE()); position.setLatitude(buf.readFloatLE()); @@ -203,7 +248,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { } else { - getLastLocation(position, dateBuilder.getDate()); + getLastLocation(position, readDate(buf)); int mcc = buf.readUnsignedShortLE(); int mnc = buf.readUnsignedShortLE(); @@ -219,8 +264,46 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { } - if (buf.readableBytes() >= 2) { + if (header == 0x2727) { + + byte[] accelerationBytes = new byte[5]; + buf.readBytes(accelerationBytes); + long acceleration = new BigInteger(accelerationBytes).longValue(); + double accelerationZ = BitUtil.between(acceleration, 8, 15) + BitUtil.between(acceleration, 4, 8) * 0.1; + if (!BitUtil.check(acceleration, 15)) { + accelerationZ = -accelerationZ; + } + double accelerationY = BitUtil.between(acceleration, 20, 27) + BitUtil.between(acceleration, 16, 20) * 0.1; + if (!BitUtil.check(acceleration, 27)) { + accelerationY = -accelerationY; + } + double accelerationX = BitUtil.between(acceleration, 28, 32) + BitUtil.between(acceleration, 32, 39) * 0.1; + if (!BitUtil.check(acceleration, 39)) { + accelerationX = -accelerationX; + } + position.set(Position.KEY_G_SENSOR, "[" + accelerationX + "," + accelerationY + "," + accelerationZ + "]"); + + position.set(Position.KEY_BATTERY_LEVEL, BcdUtil.readInteger(buf, 2)); + position.set(Position.KEY_DEVICE_TEMP, (int) buf.readByte()); + position.set("lightSensor", BcdUtil.readInteger(buf, 2) * 0.1); + position.set(Position.KEY_BATTERY, BcdUtil.readInteger(buf, 2) * 0.1); + position.set("solarPanel", BcdUtil.readInteger(buf, 2) * 0.1); + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + + int inputStatus = buf.readUnsignedShort(); + position.set(Position.KEY_IGNITION, BitUtil.check(inputStatus, 2)); + position.set(Position.KEY_RSSI, BitUtil.between(inputStatus, 4, 11)); + + buf.readUnsignedShort(); // ignition on upload interval + buf.readUnsignedInt(); // ignition off upload interval + buf.readUnsignedByte(); // angle upload interval + buf.readUnsignedShort(); // distance upload interval + buf.readUnsignedByte(); // heartbeat + + } else if (buf.readableBytes() >= 2) { + position.set(Position.KEY_POWER, BcdUtil.readInteger(buf, 4) * 0.01); + } sendResponse(channel, header, type, index, imei, alarm); diff --git a/src/main/java/org/traccar/protocol/T800xProtocolEncoder.java b/src/main/java/org/traccar/protocol/T800xProtocolEncoder.java index 34f30b147..74587c8b1 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/T800xProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -17,9 +17,11 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; import org.traccar.BaseProtocolEncoder; import org.traccar.helper.DataConverter; import org.traccar.model.Command; +import org.traccar.Protocol; import java.nio.charset.StandardCharsets; @@ -29,12 +31,15 @@ public class T800xProtocolEncoder extends BaseProtocolEncoder { public static final int MODE_BROADCAST = 0x02; public static final int MODE_FORWARD = 0x03; - private ByteBuf encodeContent(Command command, String content) { + public T800xProtocolEncoder(Protocol protocol) { + super(protocol); + } + + private ByteBuf encodeContent(Command command, short header, String content) { ByteBuf buf = Unpooled.buffer(); - buf.writeByte('%'); - buf.writeByte('%'); + buf.writeShort(header); buf.writeByte(T800xProtocolDecoder.MSG_COMMAND); buf.writeShort(7 + 8 + 1 + content.length()); buf.writeShort(1); // serial number @@ -46,11 +51,16 @@ public class T800xProtocolEncoder extends BaseProtocolEncoder { } @Override - protected Object encodeCommand(Command command) { + protected Object encodeCommand(Channel channel, Command command) { + + short header = T800xProtocolDecoder.DEFAULT_HEADER; + if (channel != null) { + header = channel.pipeline().get(T800xProtocolDecoder.class).getHeader(); + } switch (command.getType()) { case Command.TYPE_CUSTOM: - return encodeContent(command, command.getString(Command.KEY_DATA)); + return encodeContent(command, header, command.getString(Command.KEY_DATA)); default: return null; } diff --git a/src/main/java/org/traccar/protocol/TechTltProtocol.java b/src/main/java/org/traccar/protocol/TechTltProtocol.java index 69a12532c..0cffb452d 100644 --- a/src/main/java/org/traccar/protocol/TechTltProtocol.java +++ b/src/main/java/org/traccar/protocol/TechTltProtocol.java @@ -29,7 +29,7 @@ public class TechTltProtocol extends BaseProtocol { protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Ardi01ProtocolDecoder(TechTltProtocol.this)); + pipeline.addLast(new TechTltProtocolDecoder(TechTltProtocol.this)); } }); } diff --git a/src/main/java/org/traccar/protocol/TechTltProtocolDecoder.java b/src/main/java/org/traccar/protocol/TechTltProtocolDecoder.java index bad289060..17f5c80fa 100644 --- a/src/main/java/org/traccar/protocol/TechTltProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TechTltProtocolDecoder.java @@ -35,6 +35,15 @@ public class TechTltProtocolDecoder extends BaseProtocolDecoder { super(protocol); } + private static final Pattern PATTERN_STATUS = new PatternBuilder() + .number("(d+),") // id + .text("INFOGPRS,") + .number("V Bat=(d+.d),") // battery + .number("TEMP=(d+),") // temperature + .expression("[^,]*,") + .number("(d+)") // rssi + .compile(); + private static final Pattern PATTERN_POSITION = new PatternBuilder() .number("(d+)") // id .text("*POS=Y,") @@ -52,11 +61,33 @@ public class TechTltProtocolDecoder extends BaseProtocolDecoder { .number("(d+)") // cid .compile(); - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + private Position decodeStatus(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_POSITION, (String) msg); + Parser parser = new Parser(PATTERN_STATUS, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_BATTERY, parser.nextDouble()); + position.set(Position.KEY_DEVICE_TEMP, parser.nextInt()); + position.set(Position.KEY_RSSI, parser.nextInt()); + + return position; + } + + private Position decodeLocation(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_POSITION, sentence); if (!parser.matches()) { return null; } @@ -84,4 +115,18 @@ public class TechTltProtocolDecoder extends BaseProtocolDecoder { return position; } + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = ((String) msg).trim(); + if (sentence.contains("INFO")) { + return decodeStatus(channel, remoteAddress, sentence); + } else if (sentence.contains("POS")) { + return decodeLocation(channel, remoteAddress, sentence); + } else { + return null; + } + } + } diff --git a/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java b/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java index 6d5e8f21e..457687b2e 100644 --- a/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2014 - 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. @@ -42,8 +42,8 @@ public class TelicProtocolDecoder extends BaseProtocolDecoder { .number("(dd)(dd)(dd)") // date (ddmmyy) .number("(dd)(dd)(dd),") // time (hhmmss) .groupBegin() - .number("(ddd)(dd)(dddd),") // longitude - .number("(dd)(dd)(dddd),") // latitude + .number("(-?d{9}),") // longitude + .number("(-?d{8}),") // latitude .or() .number("(-?d+),") // longitude .number("(-?d+),") // latitude @@ -88,17 +88,16 @@ public class TelicProtocolDecoder extends BaseProtocolDecoder { return null; } - Position position = new Position(getProtocolName()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); if (deviceSession == null) { return null; } + + Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - int event = parser.nextInt(0); + int event = parser.nextInt(); position.set(Position.KEY_EVENT, event); - position.set(Position.KEY_ALARM, decodeAlarm(event)); if (event == 11) { @@ -109,25 +108,22 @@ public class TelicProtocolDecoder extends BaseProtocolDecoder { position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - if (parser.hasNext(6)) { - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN)); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN)); + if (parser.hasNext(2)) { + position.setLongitude(parser.nextDouble() / 1000000); + position.setLatitude(parser.nextDouble() / 1000000); } if (parser.hasNext(2)) { - position.setLongitude(parser.nextDouble(0) / 10000); - position.setLatitude(parser.nextDouble(0) / 10000); + position.setLongitude(parser.nextDouble() / 10000); + position.setLatitude(parser.nextDouble() / 10000); } - position.setValid(parser.nextInt(0) != 1); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - - if (parser.hasNext()) { - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - } + position.setValid(parser.nextInt() != 1); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + position.setCourse(parser.nextDouble()); - position.set(Position.KEY_BATTERY, parser.nextInt(0)); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_BATTERY, parser.nextInt()); return position; } diff --git a/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java index 4d4d79d8d..c30fee6e3 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -29,12 +29,14 @@ public class TeltonikaFrameDecoder extends BaseFrameDecoder { protected Object decode( ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - // Check minimum length + while (buf.isReadable() && buf.getByte(buf.readerIndex()) == (byte) 0xff) { + buf.skipBytes(1); + } + if (buf.readableBytes() < MESSAGE_MINIMUM_LENGTH) { return null; } - // Read packet int length = buf.getUnsignedShort(buf.readerIndex()); if (length > 0) { if (buf.readableBytes() >= (length + 2)) { diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocol.java b/src/main/java/org/traccar/protocol/TeltonikaProtocol.java index eef9662d7..5817b86be 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocol.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,14 +29,14 @@ public class TeltonikaProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new TeltonikaFrameDecoder()); - pipeline.addLast(new TeltonikaProtocolEncoder()); + pipeline.addLast(new TeltonikaProtocolEncoder(TeltonikaProtocol.this)); pipeline.addLast(new TeltonikaProtocolDecoder(TeltonikaProtocol.this, false)); } }); addServer(new TrackerServer(true, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new TeltonikaProtocolEncoder()); + pipeline.addLast(new TeltonikaProtocolEncoder(TeltonikaProtocol.this)); pipeline.addLast(new TeltonikaProtocolDecoder(TeltonikaProtocol.this, true)); } }); diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 485df833a..c634d2438 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -157,7 +157,19 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } if (readable) { - position.set(Position.KEY_RESULT, buf.readSlice(length).toString(StandardCharsets.US_ASCII)); + String data = buf.readSlice(length).toString(StandardCharsets.US_ASCII).trim(); + if (data.startsWith("UUUUww") && data.endsWith("SSS")) { + String[] values = data.substring(6, data.length() - 4).split(";"); + for (int i = 0; i < 8; i++) { + position.set("axle" + (i + 1), Double.parseDouble(values[i])); + } + position.set("loadTruck", Double.parseDouble(values[8])); + position.set("loadTrailer", Double.parseDouble(values[9])); + position.set("totalTruck", Double.parseDouble(values[10])); + position.set("totalTrailer", Double.parseDouble(values[11])); + } else { + position.set(Position.KEY_RESULT, data); + } } else { position.set(Position.KEY_RESULT, ByteBufUtil.hexDump(buf.readSlice(length))); } diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolEncoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolEncoder.java index 5380cf3a0..8a614618a 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolEncoder.java @@ -19,6 +19,7 @@ import org.traccar.BaseProtocolEncoder; import org.traccar.helper.Checksum; import org.traccar.helper.DataConverter; import org.traccar.model.Command; +import org.traccar.Protocol; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -27,6 +28,10 @@ import java.nio.charset.StandardCharsets; public class TeltonikaProtocolEncoder extends BaseProtocolEncoder { + public TeltonikaProtocolEncoder(Protocol protocol) { + super(protocol); + } + private ByteBuf encodeContent(byte[] content) { ByteBuf buf = Unpooled.buffer(); diff --git a/src/main/java/org/traccar/protocol/Tk103Protocol.java b/src/main/java/org/traccar/protocol/Tk103Protocol.java index fa83133e2..ff0bedfb7 100644 --- a/src/main/java/org/traccar/protocol/Tk103Protocol.java +++ b/src/main/java/org/traccar/protocol/Tk103Protocol.java @@ -1,6 +1,6 @@ /* * Copyright 2017 Christoph Krey (c@ckrey.de) - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,7 +51,7 @@ public class Tk103Protocol extends BaseProtocol { pipeline.addLast(new Tk103FrameDecoder()); pipeline.addLast(new StringDecoder()); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Tk103ProtocolEncoder()); + pipeline.addLast(new Tk103ProtocolEncoder(Tk103Protocol.this)); pipeline.addLast(new Tk103ProtocolDecoder(Tk103Protocol.this)); } }); @@ -60,7 +60,7 @@ public class Tk103Protocol extends BaseProtocol { protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new StringDecoder()); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Tk103ProtocolEncoder()); + pipeline.addLast(new Tk103ProtocolEncoder(Tk103Protocol.this)); pipeline.addLast(new Tk103ProtocolDecoder(Tk103Protocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java index 98edc8cb5..a8aa84105 100644 --- a/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java @@ -1,6 +1,6 @@ /* * Copyright 2017 Christoph Krey (c@ckrey.de) - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -19,16 +19,19 @@ package org.traccar.protocol; import org.traccar.Context; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class Tk103ProtocolEncoder extends StringProtocolEncoder { private final boolean forceAlternative; - public Tk103ProtocolEncoder() { + public Tk103ProtocolEncoder(Protocol protocol) { + super(protocol); this.forceAlternative = false; } - public Tk103ProtocolEncoder(boolean forceAlternative) { + public Tk103ProtocolEncoder(Protocol protocol, boolean forceAlternative) { + super(protocol); this.forceAlternative = forceAlternative; } @@ -40,7 +43,7 @@ public class Tk103ProtocolEncoder extends StringProtocolEncoder { protected Object encodeCommand(Command command) { boolean alternative = forceAlternative || Context.getIdentityManager().lookupAttributeBoolean( - command.getDeviceId(), "tk103.alternative", false, true); + command.getDeviceId(), getProtocolName() + ".alternative", false, false, true); initDevicePassword(command, "123456"); diff --git a/src/main/java/org/traccar/protocol/TotemProtocol.java b/src/main/java/org/traccar/protocol/TotemProtocol.java index 66e1ec4f1..f8cda8358 100644 --- a/src/main/java/org/traccar/protocol/TotemProtocol.java +++ b/src/main/java/org/traccar/protocol/TotemProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ public class TotemProtocol extends BaseProtocol { pipeline.addLast(new TotemFrameDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new TotemProtocolEncoder()); + pipeline.addLast(new TotemProtocolEncoder(TotemProtocol.this)); pipeline.addLast(new TotemProtocolDecoder(TotemProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java b/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java index b5049859d..3bbb92031 100644 --- a/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java @@ -1,6 +1,6 @@ /* * Copyright 2015 Irving Gonzalez - * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class TotemProtocolEncoder extends StringProtocolEncoder { + public TotemProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java b/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java index aaaaccb60..e4c94dc77 100644 --- a/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ public class TramigoFrameDecoder extends BaseFrameDecoder { length = buf.getUnsignedShort(buf.readerIndex() + 6); } - if (length >= buf.readableBytes()) { + if (length <= buf.readableBytes()) { return buf.readRetainedSlice(length); } diff --git a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java index b63385187..05312b820 100644 --- a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,7 +42,8 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN = new PatternBuilder() .expression("[A-Z]{2,3}") - .number("APdd") + .expression("[A-Z]P") + .number("dd") .number("(dd)(dd)(dd)") // date (yymmdd) .expression("([AV])") // validity .number("(dd)(dd.d+)") // latitude @@ -57,7 +58,8 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { .number("(ddd)") // battery .number("(d)") // acc .number("(dd)") // arm status - .number("(dd),") // working mode + .number("(dd)") // working mode + .number("(?:[0-2]{3})?,") .number("(d+),") // mcc .number("(d+),") // mnc .number("(d+),") // lac @@ -181,7 +183,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { return position; - } else if (type.equals("AP01") || type.equals("AP10")) { + } else if (type.equals("AP01") || type.equals("AP10") || type.equals("YP03")) { Parser parser = new Parser(PATTERN, sentence); if (!parser.matches()) { diff --git a/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java index 87b44a4b2..4f6854098 100644 --- a/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ 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; @@ -67,7 +68,17 @@ public class TzoneProtocolDecoder extends BaseProtocolDecoder { return false; } - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + if (hardware == 0x413) { + buf.readUnsignedByte(); // status + } else { + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + } + + if (hardware == 0x413) { + position.setFixTime(new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()).getDate()); + } double lat; double lon; @@ -80,25 +91,39 @@ public class TzoneProtocolDecoder extends BaseProtocolDecoder { lon = buf.readUnsignedInt() / 100000.0 / 60.0; } - position.setFixTime(new DateBuilder() - .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()).getDate()); + if (hardware == 0x413) { - position.setSpeed(buf.readUnsignedShort() * 0.01); + position.set(Position.KEY_HDOP, buf.readUnsignedShort() * 0.1); - position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium()); + position.setAltitude(buf.readUnsignedShort()); + position.setCourse(buf.readUnsignedShort()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort() * 0.1)); + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + + } else { + + position.setFixTime(new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()).getDate()); + + position.setSpeed(buf.readUnsignedShort() * 0.01); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium()); + + int flags = buf.readUnsignedShort(); + position.setCourse(BitUtil.to(flags, 9)); + if (!BitUtil.check(flags, 10)) { + lat = -lat; + } + position.setLatitude(lat); + if (BitUtil.check(flags, 9)) { + lon = -lon; + } + position.setLongitude(lon); + position.setValid(BitUtil.check(flags, 11)); - int flags = buf.readUnsignedShort(); - position.setCourse(BitUtil.to(flags, 9)); - if (!BitUtil.check(flags, 10)) { - lat = -lat; - } - position.setLatitude(lat); - if (BitUtil.check(flags, 9)) { - lon = -lon; } - position.setLongitude(lon); - position.setValid(BitUtil.check(flags, 11)); buf.readerIndex(blockEnd); diff --git a/src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java b/src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java index 0a2a59e23..7fec0bf8b 100644 --- a/src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java @@ -237,12 +237,13 @@ public class UlbotechProtocolDecoder extends BaseProtocolDecoder { case DATA_GPS: hasLocation = true; - position.setValid(true); position.setLatitude(buf.readInt() / 1000000.0); position.setLongitude(buf.readInt() / 1000000.0); position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); position.setCourse(buf.readUnsignedShort()); - position.set(Position.KEY_HDOP, buf.readUnsignedShort()); + int hdop = buf.readUnsignedShort(); + position.setValid(hdop < 9999); + position.set(Position.KEY_HDOP, hdop * 0.01); break; case DATA_LBS: diff --git a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java index dc7a9200d..873b22006 100644 --- a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 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. @@ -89,6 +89,13 @@ public class UproProtocolDecoder extends BaseProtocolDecoder { } } + private String decodeAlarm(int alarm) { + if (BitUtil.check(alarm, 2)) { + return Position.ALARM_TAMPERING; + } + return null; + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -160,9 +167,25 @@ public class UproProtocolDecoder extends BaseProtocolDecoder { position.setSpeed( Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)) * 0.1); break; + case 'G': + position.setAltitude( + Integer.parseInt(data.readSlice(6).toString(StandardCharsets.US_ASCII)) * 0.1); + 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); + break; + case 'N': + position.set(Position.KEY_RSSI, + Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII))); + break; + case 'O': + position.set(Position.KEY_SATELLITES, + Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII))); + break; case 'P': if (data.readableBytes() >= 16) { position.setNetwork(new Network(CellTower.from( @@ -188,25 +211,53 @@ public class UproProtocolDecoder extends BaseProtocolDecoder { case 'S': position.set("obdTraffic", ByteBufUtil.hexDump(data)); break; - case 'T': - position.set(Position.KEY_BATTERY_LEVEL, - Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII))); - break; case 'V': position.set(Position.KEY_POWER, Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)) * 0.1); break; + case 'W': + position.set(Position.KEY_ALARM, + decodeAlarm(Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII)))); + break; + case 'X': + Network network = new Network(); + int mcc = 0, mnc = 0; + String[] cells = data.toString(StandardCharsets.US_ASCII).split(";"); + if (!cells[0].startsWith("(")) { + for (int i = 0; i < cells.length; i++) { + String[] values = cells[i].split(","); + int index = 0; + if (i == 0) { + mcc = Integer.parseInt(values[index++]); + mnc = Integer.parseInt(values[index++]); + } + network.addCellTower(CellTower.from( + mcc, mnc, + Integer.parseInt(values[index++]), + Integer.parseInt(values[index++]), + Integer.parseInt(values[index]))); + } + position.setNetwork(network); + } + break; + case 'Y': + position.set(Position.KEY_POWER, + Integer.parseInt(data.readSlice(5).toString(StandardCharsets.US_ASCII)) * 0.001); + break; default: break; } } - if (position.getLatitude() != 0 && position.getLongitude() != 0) { - return position; + if (position.getLatitude() == 0 || position.getLongitude() == 0) { + if (position.getAttributes().isEmpty()) { + return null; + } + getLastLocation(position, position.getDeviceTime()); } - return null; + return position; } } diff --git a/src/main/java/org/traccar/protocol/WatchProtocol.java b/src/main/java/org/traccar/protocol/WatchProtocol.java index fe285e70d..6dc3bf9fb 100644 --- a/src/main/java/org/traccar/protocol/WatchProtocol.java +++ b/src/main/java/org/traccar/protocol/WatchProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,7 +44,7 @@ public class WatchProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new WatchFrameDecoder()); - pipeline.addLast(new WatchProtocolEncoder()); + pipeline.addLast(new WatchProtocolEncoder(WatchProtocol.this)); pipeline.addLast(new WatchProtocolDecoder(WatchProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java b/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java index 70b207e9b..0647afdee 100644 --- a/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java @@ -249,8 +249,7 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder { } } - } else if (type.equals("UD") || type.equals("UD2") || type.equals("UD3") - || type.equals("AL") || type.equals("WT")) { + } else if (type.startsWith("UD") || type.equals("AL") || type.equals("WT")) { Position position = decodePosition(deviceSession, buf.toString(StandardCharsets.US_ASCII)); @@ -267,7 +266,10 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder { sendResponse(channel, id, index, "TKQ"); - } else if (type.equals("PULSE") || type.equals("heart") || type.equals("bphrt")) { + } else if (type.equalsIgnoreCase("PULSE") + || type.equalsIgnoreCase("HEART") + || type.equalsIgnoreCase("BLOOD") + || type.equalsIgnoreCase("BPHRT")) { if (buf.isReadable()) { @@ -279,11 +281,14 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder { String[] values = buf.toString(StandardCharsets.US_ASCII).split(","); int valueIndex = 0; - if (type.equals("bphrt")) { + if (type.equalsIgnoreCase("BPHRT") || type.equalsIgnoreCase("BLOOD")) { position.set("pressureHigh", values[valueIndex++]); position.set("pressureLow", values[valueIndex++]); } - position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[valueIndex])); + + if (valueIndex <= values.length - 1) { + position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[valueIndex])); + } return position; diff --git a/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java b/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java index 264aec81f..b433dfd2a 100644 --- a/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -21,6 +21,7 @@ import io.netty.channel.Channel; import org.traccar.StringProtocolEncoder; import org.traccar.helper.DataConverter; import org.traccar.model.Command; +import org.traccar.Protocol; import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; @@ -32,6 +33,10 @@ import java.util.TimeZone; public class WatchProtocolEncoder extends StringProtocolEncoder implements StringProtocolEncoder.ValueFormatter { + public WatchProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override public String formatValue(String key, Object value) { if (key.equals(Command.KEY_TIMEZONE)) { diff --git a/src/main/java/org/traccar/protocol/WialonProtocol.java b/src/main/java/org/traccar/protocol/WialonProtocol.java index 06b54dceb..fd183dd2c 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocol.java +++ b/src/main/java/org/traccar/protocol/WialonProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,14 +38,31 @@ public class WialonProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new LineBasedFrameDecoder(4 * 1024)); - pipeline.addLast(new StringEncoder()); boolean utf8 = Context.getConfig().getBoolean(getName() + ".utf8"); if (utf8) { + pipeline.addLast(new StringEncoder(StandardCharsets.UTF_8)); pipeline.addLast(new StringDecoder(StandardCharsets.UTF_8)); } else { + pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); } - pipeline.addLast(new WialonProtocolEncoder()); + pipeline.addLast(new WialonProtocolEncoder(WialonProtocol.this)); + pipeline.addLast(new WialonProtocolDecoder(WialonProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(4 * 1024)); + boolean utf8 = Context.getConfig().getBoolean(getName() + ".utf8"); + if (utf8) { + pipeline.addLast(new StringEncoder(StandardCharsets.UTF_8)); + pipeline.addLast(new StringDecoder(StandardCharsets.UTF_8)); + } else { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + } + pipeline.addLast(new WialonProtocolEncoder(WialonProtocol.this)); pipeline.addLast(new WialonProtocolDecoder(WialonProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java index 42ff3177e..8488ca2d1 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java @@ -38,6 +38,14 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { super(protocol); } + private static final Pattern PATTERN_ANY = new PatternBuilder() + .expression("([^#]*)?") // imei + .text("#") // start byte + .expression("([^#]+)") // type + .text("#") // separator + .expression("(.*)") // message + .compile(); + private static final Pattern PATTERN = new PatternBuilder() .number("(dd)(dd)(dd);") // date (ddmmyy) .number("(dd)(dd)(dd);") // time (hhmmss) @@ -62,7 +70,8 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { private void sendResponse(Channel channel, SocketAddress remoteAddress, String type, Integer number) { if (channel != null) { StringBuilder response = new StringBuilder("#A"); - response.append(type.substring(1)); + response.append(type); + response.append("#"); if (number != null) { response.append(number); } @@ -71,9 +80,9 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { } } - private Position decodePosition(Channel channel, SocketAddress remoteAddress, String substring) { + private Position decodePosition(Channel channel, SocketAddress remoteAddress, String id, String substring) { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); if (deviceSession == null) { return null; } @@ -135,12 +144,20 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { String sentence = (String) msg; - String type = sentence.substring(0, sentence.indexOf('#', 1) + 1); + + Parser parser = new Parser(PATTERN_ANY, sentence); + if (!parser.matches()) { + return null; + } + + String id = parser.next(); + String type = parser.next(); + String data = parser.next(); switch (type) { - case "#L#": - String[] values = sentence.substring(3).split(";"); + case "L": + String[] values = data.split(";"); String imei = values[0].indexOf('.') >= 0 ? values[1] : values[0]; DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); @@ -149,14 +166,14 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { } break; - case "#P#": + case "P": sendResponse(channel, remoteAddress, type, null); // heartbeat break; - case "#D#": - case "#SD#": + case "D": + case "SD": Position position = decodePosition( - channel, remoteAddress, sentence.substring(sentence.indexOf('#', 1) + 1)); + channel, remoteAddress, id, data); if (position != null) { sendResponse(channel, remoteAddress, type, 1); @@ -164,12 +181,12 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { } break; - case "#B#": - String[] messages = sentence.substring(sentence.indexOf('#', 1) + 1).split("\\|"); + case "B": + String[] messages = data.split("\\|"); List<Position> positions = new LinkedList<>(); for (String message : messages) { - position = decodePosition(channel, remoteAddress, message); + position = decodePosition(channel, remoteAddress, id, message); if (position != null) { position.set(Position.KEY_ARCHIVE, true); positions.add(position); @@ -182,14 +199,14 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { } break; - case "#M#": - deviceSession = getDeviceSession(channel, remoteAddress); + case "M": + deviceSession = getDeviceSession(channel, remoteAddress, id); if (deviceSession != null) { position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); getLastLocation(position, new Date()); position.setValid(false); - position.set(Position.KEY_RESULT, sentence.substring(sentence.indexOf('#', 1) + 1)); + position.set(Position.KEY_RESULT, data); sendResponse(channel, remoteAddress, type, 1); return position; } diff --git a/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java b/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java index 9ff1631eb..c45edf00d 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,9 +18,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class WialonProtocolEncoder extends StringProtocolEncoder { + public WialonProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { switch (command.getType()) { diff --git a/src/main/java/org/traccar/protocol/WondexProtocol.java b/src/main/java/org/traccar/protocol/WondexProtocol.java index 8c6283d66..035dd9160 100644 --- a/src/main/java/org/traccar/protocol/WondexProtocol.java +++ b/src/main/java/org/traccar/protocol/WondexProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,6 @@ import io.netty.handler.codec.string.StringEncoder; public class WondexProtocol extends BaseProtocol { public WondexProtocol() { - setTextCommandEncoder(new WondexProtocolEncoder()); setSupportedCommands( Command.TYPE_GET_DEVICE_STATUS, Command.TYPE_GET_MODEM_STATUS, @@ -33,12 +32,13 @@ public class WondexProtocol extends BaseProtocol { Command.TYPE_POSITION_SINGLE, Command.TYPE_GET_VERSION, Command.TYPE_IDENTIFICATION); + setTextCommandEncoder(new WondexProtocolEncoder(this)); addServer(new TrackerServer(false, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new WondexFrameDecoder()); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new WondexProtocolEncoder()); + pipeline.addLast(new WondexProtocolEncoder(WondexProtocol.this)); pipeline.addLast(new WondexProtocolDecoder(WondexProtocol.this)); } }); @@ -46,7 +46,7 @@ public class WondexProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new StringEncoder()); - pipeline.addLast(new WondexProtocolEncoder()); + pipeline.addLast(new WondexProtocolEncoder(WondexProtocol.this)); pipeline.addLast(new WondexProtocolDecoder(WondexProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java b/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java index f9e8eeb9b..e9bb23d15 100644 --- a/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -17,9 +17,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class WondexProtocolEncoder extends StringProtocolEncoder { + public WondexProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/XexunProtocol.java b/src/main/java/org/traccar/protocol/XexunProtocol.java index 0005270fb..401844e7b 100644 --- a/src/main/java/org/traccar/protocol/XexunProtocol.java +++ b/src/main/java/org/traccar/protocol/XexunProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,7 +42,7 @@ public class XexunProtocol extends BaseProtocol { } pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new XexunProtocolEncoder()); + pipeline.addLast(new XexunProtocolEncoder(XexunProtocol.this)); pipeline.addLast(new XexunProtocolDecoder(XexunProtocol.this, full)); } }); diff --git a/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java b/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java index 515cfbbd0..fc849fe15 100644 --- a/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -17,9 +17,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class XexunProtocolEncoder extends StringProtocolEncoder { + public XexunProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/XirgoProtocol.java b/src/main/java/org/traccar/protocol/XirgoProtocol.java index 4979fda5d..1be5b6c4b 100644 --- a/src/main/java/org/traccar/protocol/XirgoProtocol.java +++ b/src/main/java/org/traccar/protocol/XirgoProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ public class XirgoProtocol extends BaseProtocol { pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "##")); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new XirgoProtocolEncoder()); + pipeline.addLast(new XirgoProtocolEncoder(XirgoProtocol.this)); pipeline.addLast(new XirgoProtocolDecoder(XirgoProtocol.this)); } }); @@ -44,7 +44,7 @@ public class XirgoProtocol extends BaseProtocol { protected void addProtocolHandlers(PipelineBuilder pipeline) { pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new XirgoProtocolEncoder()); + pipeline.addLast(new XirgoProtocolEncoder(XirgoProtocol.this)); pipeline.addLast(new XirgoProtocolDecoder(XirgoProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java b/src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java index 08809307f..4d0cc314b 100644 --- a/src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java @@ -266,7 +266,7 @@ public class XirgoProtocolDecoder extends BaseProtocolDecoder { position.setValid(Integer.parseInt(values[i]) == 3); break; case "SI": - position.set("iccid", values[i]); + position.set(Position.KEY_ICCID, values[i]); break; case "IG": int ignition = Integer.parseInt(values[i]); diff --git a/src/main/java/org/traccar/protocol/XirgoProtocolEncoder.java b/src/main/java/org/traccar/protocol/XirgoProtocolEncoder.java index dd5e30cca..aa85e9e0e 100644 --- a/src/main/java/org/traccar/protocol/XirgoProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/XirgoProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -17,9 +17,14 @@ package org.traccar.protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class XirgoProtocolEncoder extends StringProtocolEncoder { + public XirgoProtocolEncoder(Protocol protocol) { + super(protocol); + } + @Override protected Object encodeCommand(Command command) { diff --git a/src/main/java/org/traccar/protocol/Xrb28Protocol.java b/src/main/java/org/traccar/protocol/Xrb28Protocol.java index b1f1c34fb..5d8af418b 100644 --- a/src/main/java/org/traccar/protocol/Xrb28Protocol.java +++ b/src/main/java/org/traccar/protocol/Xrb28Protocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 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. @@ -40,7 +40,7 @@ public class Xrb28Protocol extends BaseProtocol { pipeline.addLast(new LineBasedFrameDecoder(1024)); pipeline.addLast(new StringEncoder(StandardCharsets.ISO_8859_1)); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Xrb28ProtocolEncoder()); + pipeline.addLast(new Xrb28ProtocolEncoder(Xrb28Protocol.this)); pipeline.addLast(new Xrb28ProtocolDecoder(Xrb28Protocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/Xrb28ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Xrb28ProtocolEncoder.java index 617639312..3e69af329 100644 --- a/src/main/java/org/traccar/protocol/Xrb28ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Xrb28ProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 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. @@ -18,9 +18,14 @@ package org.traccar.protocol; import io.netty.channel.Channel; import org.traccar.BaseProtocolEncoder; import org.traccar.model.Command; +import org.traccar.Protocol; public class Xrb28ProtocolEncoder extends BaseProtocolEncoder { + public Xrb28ProtocolEncoder(Protocol protocol) { + super(protocol); + } + private String formatCommand(Command command, String content) { return String.format("\u00ff\u00ff*SCOS,OM,%s,%s#\n", getUniqueId(command.getDeviceId()), content); } diff --git a/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java index 819011a50..c132f194b 100644 --- a/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -59,7 +59,7 @@ public class Xt2400ProtocolDecoder extends BaseProtocolDecoder { 0x26, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x57, 0x58, 0x59, 0x5a, 0x6b, 0x6f, 0x7A, 0x7B, 0x7C, 0x7d, 0x7E, 0x7F, 0x80, 0x81, 0x82, - 0x83, 0x84, 0x85, 0x86 + 0x83, 0x84, 0x85, 0x86, 0xc8 }; int[] l4 = { 0x03, 0x06, 0x07, 0x08, 0x0e, 0x0f, 0x10, 0x11, @@ -80,12 +80,13 @@ public class Xt2400ProtocolDecoder extends BaseProtocolDecoder { TAG_LENGTH_MAP.put(i, 4); } TAG_LENGTH_MAP.put(0x95, 24); + TAG_LENGTH_MAP.put(0xD0, 21); } private static int getTagLength(int tag) { Integer length = TAG_LENGTH_MAP.get(tag); if (length == null) { - throw new IllegalArgumentException("Unknown tag: " + tag); + throw new IllegalArgumentException(String.format("Unknown tag: 0x%02X", tag)); } return length; } @@ -93,7 +94,7 @@ public class Xt2400ProtocolDecoder extends BaseProtocolDecoder { private Map<Short, byte[]> formats = new HashMap<>(); public void setConfig(String configString) { - Pattern pattern = Pattern.compile(":wycfg pcr\\[\\d+\\] ([0-9a-fA-F]{2})[0-9a-fA-F]{2}([0-9a-fA-F]+)"); + Pattern pattern = Pattern.compile(":wycfg pcr\\[\\d+] ([0-9a-fA-F]{2})[0-9a-fA-F]{2}([0-9a-fA-F]+)"); Matcher matcher = pattern.matcher(configString); while (matcher.find()) { formats.put(Short.parseShort(matcher.group(1), 16), DataConverter.parseHex(matcher.group(2))); @@ -119,7 +120,8 @@ public class Xt2400ProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); - for (byte tag : format) { + for (byte b : format) { + int tag = b & 0xFF; switch (tag) { case 0x03: DeviceSession deviceSession = getDeviceSession( @@ -177,6 +179,14 @@ public class Xt2400ProtocolDecoder extends BaseProtocolDecoder { case 0x65: position.set(Position.KEY_VIN, buf.readSlice(17).toString(StandardCharsets.US_ASCII)); break; + case 0x6C: + buf.readUnsignedByte(); // mil + int ecuCount = buf.readUnsignedByte(); + for (int i = 0; i < ecuCount; i++) { + buf.readUnsignedByte(); // ecu id + buf.skipBytes(buf.readUnsignedByte() * 6); + } + break; case 0x73: position.set(Position.KEY_VERSION_FW, buf.readSlice(16).toString(StandardCharsets.US_ASCII).trim()); break; diff --git a/src/main/java/org/traccar/reports/Stops.java b/src/main/java/org/traccar/reports/Stops.java index 98c9cef00..2036b0641 100644 --- a/src/main/java/org/traccar/reports/Stops.java +++ b/src/main/java/org/traccar/reports/Stops.java @@ -43,7 +43,7 @@ public final class Stops { private static Collection<StopReport> detectStops(long deviceId, Date from, Date to) throws SQLException { boolean ignoreOdometer = Context.getDeviceManager() - .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, true); + .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true); IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class); DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class); diff --git a/src/main/java/org/traccar/reports/Summary.java b/src/main/java/org/traccar/reports/Summary.java index 9810424d8..6d179a873 100644 --- a/src/main/java/org/traccar/reports/Summary.java +++ b/src/main/java/org/traccar/reports/Summary.java @@ -61,7 +61,7 @@ public final class Summary { result.setMaxSpeed(position.getSpeed()); } boolean ignoreOdometer = Context.getDeviceManager() - .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, true); + .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true); result.setDistance(ReportUtils.calculateDistance(firstPosition, previousPosition, !ignoreOdometer)); result.setAverageSpeed(speedSum / positions.size()); result.setSpentFuel(ReportUtils.calculateFuel(firstPosition, previousPosition)); diff --git a/src/main/java/org/traccar/reports/Trips.java b/src/main/java/org/traccar/reports/Trips.java index 3cda65553..7c0cd6921 100644 --- a/src/main/java/org/traccar/reports/Trips.java +++ b/src/main/java/org/traccar/reports/Trips.java @@ -42,7 +42,7 @@ public final class Trips { private static Collection<TripReport> detectTrips(long deviceId, Date from, Date to) throws SQLException { boolean ignoreOdometer = Context.getDeviceManager() - .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, true); + .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true); IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class); DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class); |