diff options
Diffstat (limited to 'src/main/java/org/traccar/protocol')
344 files changed, 5727 insertions, 1539 deletions
diff --git a/src/main/java/org/traccar/protocol/AdmProtocol.java b/src/main/java/org/traccar/protocol/AdmProtocol.java index bab1d2339..3856dc906 100644 --- a/src/main/java/org/traccar/protocol/AdmProtocol.java +++ b/src/main/java/org/traccar/protocol/AdmProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AdmProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AisProtocol.java b/src/main/java/org/traccar/protocol/AisProtocol.java index bc975c277..e792a1d3f 100644 --- a/src/main/java/org/traccar/protocol/AisProtocol.java +++ b/src/main/java/org/traccar/protocol/AisProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AisProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AlematicsProtocol.java b/src/main/java/org/traccar/protocol/AlematicsProtocol.java index b85b44382..5219607e7 100644 --- a/src/main/java/org/traccar/protocol/AlematicsProtocol.java +++ b/src/main/java/org/traccar/protocol/AlematicsProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AlematicsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AnytrekProtocol.java b/src/main/java/org/traccar/protocol/AnytrekProtocol.java index b0e974c69..5dce15ce1 100644 --- a/src/main/java/org/traccar/protocol/AnytrekProtocol.java +++ b/src/main/java/org/traccar/protocol/AnytrekProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AnytrekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ApelProtocol.java b/src/main/java/org/traccar/protocol/ApelProtocol.java index f1d6e659c..550581b85 100644 --- a/src/main/java/org/traccar/protocol/ApelProtocol.java +++ b/src/main/java/org/traccar/protocol/ApelProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ApelProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AplicomProtocol.java b/src/main/java/org/traccar/protocol/AplicomProtocol.java index 47bb780cb..48c628d22 100644 --- a/src/main/java/org/traccar/protocol/AplicomProtocol.java +++ b/src/main/java/org/traccar/protocol/AplicomProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AplicomProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AppelloProtocol.java b/src/main/java/org/traccar/protocol/AppelloProtocol.java index 25b2bf3b8..34055d7e4 100644 --- a/src/main/java/org/traccar/protocol/AppelloProtocol.java +++ b/src/main/java/org/traccar/protocol/AppelloProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AppelloProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AquilaProtocol.java b/src/main/java/org/traccar/protocol/AquilaProtocol.java index 6080df33d..bd9c34d08 100644 --- a/src/main/java/org/traccar/protocol/AquilaProtocol.java +++ b/src/main/java/org/traccar/protocol/AquilaProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AquilaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Ardi01Protocol.java b/src/main/java/org/traccar/protocol/Ardi01Protocol.java index b33c2817f..5ddbe9d62 100644 --- a/src/main/java/org/traccar/protocol/Ardi01Protocol.java +++ b/src/main/java/org/traccar/protocol/Ardi01Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Ardi01Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ArknavProtocol.java b/src/main/java/org/traccar/protocol/ArknavProtocol.java index 4f443aa3a..20fec296c 100644 --- a/src/main/java/org/traccar/protocol/ArknavProtocol.java +++ b/src/main/java/org/traccar/protocol/ArknavProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ArknavProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ArknavX8Protocol.java b/src/main/java/org/traccar/protocol/ArknavX8Protocol.java index 39c6e8009..a8be6f40c 100644 --- a/src/main/java/org/traccar/protocol/ArknavX8Protocol.java +++ b/src/main/java/org/traccar/protocol/ArknavX8Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ArknavX8Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ArmoliProtocol.java b/src/main/java/org/traccar/protocol/ArmoliProtocol.java index 32fba3b52..e9c947ecd 100644 --- a/src/main/java/org/traccar/protocol/ArmoliProtocol.java +++ b/src/main/java/org/traccar/protocol/ArmoliProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ArmoliProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ArnaviProtocol.java b/src/main/java/org/traccar/protocol/ArnaviProtocol.java index 091d5c06f..962bcce52 100644 --- a/src/main/java/org/traccar/protocol/ArnaviProtocol.java +++ b/src/main/java/org/traccar/protocol/ArnaviProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ArnaviProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java index 361eeeef2..50ceea898 100644 --- a/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java @@ -21,7 +21,7 @@ import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.Protocol; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.net.SocketAddress; public class ArnaviProtocolDecoder extends BaseProtocolDecoder { diff --git a/src/main/java/org/traccar/protocol/AstraProtocol.java b/src/main/java/org/traccar/protocol/AstraProtocol.java index 021a81e07..dcc02d10d 100644 --- a/src/main/java/org/traccar/protocol/AstraProtocol.java +++ b/src/main/java/org/traccar/protocol/AstraProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AstraProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/At2000Protocol.java b/src/main/java/org/traccar/protocol/At2000Protocol.java index 25e9be86f..c7e22f142 100644 --- a/src/main/java/org/traccar/protocol/At2000Protocol.java +++ b/src/main/java/org/traccar/protocol/At2000Protocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class At2000Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AtrackProtocol.java b/src/main/java/org/traccar/protocol/AtrackProtocol.java index 21eb09696..8b86955f4 100644 --- a/src/main/java/org/traccar/protocol/AtrackProtocol.java +++ b/src/main/java/org/traccar/protocol/AtrackProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AtrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java index 340641729..8896dcfb0 100644 --- a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java @@ -429,6 +429,208 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { case "MP": buf.readUnsignedByte(); // manifold absolute pressure break; + case "EO": + position.set(Position.KEY_ODOMETER, UnitsConverter.metersFromMiles(buf.readUnsignedInt())); + break; + case "EH": + position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 360000); + break; + case "ZO1": + buf.readUnsignedByte(); // brake stroke status + break; + case "ZO2": + buf.readUnsignedByte(); // warning indicator status + break; + case "ZO3": + buf.readUnsignedByte(); // abs control status + break; + case "ZO4": + position.set(Position.KEY_THROTTLE, buf.readUnsignedByte() * 0.4); + break; + case "ZO5": + buf.readUnsignedByte(); // parking brake status + break; + case "ZO6": + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte() * 0.805); + break; + case "ZO7": + buf.readUnsignedByte(); // cruise control status + break; + case "ZO8": + buf.readUnsignedByte(); // accelector pedal position + break; + case "ZO9": + position.set(Position.KEY_ENGINE_LOAD, buf.readUnsignedByte() * 0.5); + break; + case "ZO10": + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.5); + break; + case "ZO11": + buf.readUnsignedByte(); // engine oil pressure + break; + case "ZO12": + buf.readUnsignedByte(); // boost pressure + break; + case "ZO13": + buf.readUnsignedByte(); // intake temperature + break; + case "ZO14": + position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte()); + break; + case "ZO15": + buf.readUnsignedByte(); // brake application pressure + break; + case "ZO16": + buf.readUnsignedByte(); // brake primary pressure + break; + case "ZO17": + buf.readUnsignedByte(); // brake secondary pressure + break; + case "ZH1": + buf.readUnsignedShort(); // cargo weight + break; + case "ZH2": + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 16.428 / 3600); + break; + case "ZH3": + position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.25); + break; + case "ZL1": + buf.readUnsignedInt(); // fuel used (natural gas) + break; + case "ZL2": + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 161); + break; + case "ZL3": + buf.readUnsignedInt(); // vehicle hours + break; + case "ZL4": + position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 5 * 36000); + break; + case "ZS1": + position.set(Position.KEY_VIN, readString(buf)); + break; + case "JO1": + buf.readUnsignedByte(); // pedals + break; + case "JO2": + buf.readUnsignedByte(); // power takeoff device + break; + case "JO3": + buf.readUnsignedByte(); // accelector pedal position + break; + case "JO4": + position.set(Position.KEY_ENGINE_LOAD, buf.readUnsignedByte()); + break; + case "JO5": + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4); + break; + case "JO6": + buf.readUnsignedByte(); // fms vehicle interface + break; + case "JO7": + buf.readUnsignedByte(); // driver 2 + break; + case "JO8": + buf.readUnsignedByte(); // driver 1 + break; + case "JO9": + buf.readUnsignedByte(); // drivers + break; + case "JO10": + buf.readUnsignedByte(); // system information + break; + case "JO11": + position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte() - 40); + break; + case "JO12": + buf.readUnsignedByte(); // pto engaged + break; + case "JH1": + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() / 256.0); + break; + case "JH2": + position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.125); + break; + case "JH3": + case "JH4": + case "JH5": + case "JH6": + case "JH7": + int index = Integer.parseInt(key.substring(2)) - 2; + position.set("axleWeight" + index, buf.readUnsignedShort() * 0.5); + break; + case "JH8": + position.set(Position.KEY_ODOMETER_SERVICE, buf.readUnsignedShort() * 5); + break; + case "JH9": + buf.readUnsignedShort(); // tachograph speed + break; + case "JH10": + buf.readUnsignedShort(); // ambient air temperature + break; + case "JH11": + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 0.05); + break; + case "JH12": + buf.readUnsignedShort(); // fuel economy + break; + case "JL1": + position.set(Position.KEY_FUEL_USED, buf.readUnsignedInt() * 0.5); + break; + case "JL2": + position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 5 * 36000); + break; + case "JL3": + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 1000); + break; + case "JL4": + position.set(Position.KEY_FUEL_USED, buf.readUnsignedInt() * 0.001); + break; + case "JS1": + position.set(Position.KEY_VIN, readString(buf)); + break; + case "JS2": + readString(buf); // fms version supported + break; + case "JS3": + position.set("driver1", readString(buf)); + break; + case "JS4": + position.set("driver2", readString(buf)); + break; + case "JN1": + buf.readUnsignedInt(); // cruise control distance + break; + case "JN2": + buf.readUnsignedInt(); // excessive idling time + break; + case "JN3": + buf.readUnsignedInt(); // excessive idling fuel + break; + case "JN4": + buf.readUnsignedInt(); // pto time + break; + case "JN5": + buf.readUnsignedInt(); // pto fuel + break; + case "IN0": + position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); + break; + case "IN1": + case "IN2": + case "IN3": + position.set(Position.PREFIX_IN + key.charAt(2), buf.readUnsignedByte() > 0); + break; + case "HA": + position.set(Position.KEY_ALARM, buf.readUnsignedByte() > 0 ? Position.ALARM_ACCELERATION : null); + break; + case "HB": + position.set(Position.KEY_ALARM, buf.readUnsignedByte() > 0 ? Position.ALARM_BRAKING : null); + break; + case "HC": + position.set(Position.KEY_ALARM, buf.readUnsignedByte() > 0 ? Position.ALARM_CORNERING : null); + break; default: break; } diff --git a/src/main/java/org/traccar/protocol/AuroProtocol.java b/src/main/java/org/traccar/protocol/AuroProtocol.java index d37884c8b..728c8e23c 100644 --- a/src/main/java/org/traccar/protocol/AuroProtocol.java +++ b/src/main/java/org/traccar/protocol/AuroProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AuroProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AustinNbProtocol.java b/src/main/java/org/traccar/protocol/AustinNbProtocol.java index 6a68467e2..467deff53 100644 --- a/src/main/java/org/traccar/protocol/AustinNbProtocol.java +++ b/src/main/java/org/traccar/protocol/AustinNbProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AustinNbProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AutoFonProtocol.java b/src/main/java/org/traccar/protocol/AutoFonProtocol.java index 0566b1da6..75bd28d5e 100644 --- a/src/main/java/org/traccar/protocol/AutoFonProtocol.java +++ b/src/main/java/org/traccar/protocol/AutoFonProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AutoFonProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AutoGradeProtocol.java b/src/main/java/org/traccar/protocol/AutoGradeProtocol.java index bc80e473a..69d9fb4e6 100644 --- a/src/main/java/org/traccar/protocol/AutoGradeProtocol.java +++ b/src/main/java/org/traccar/protocol/AutoGradeProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AutoGradeProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AutoTrackProtocol.java b/src/main/java/org/traccar/protocol/AutoTrackProtocol.java index 80255d3e9..df489de3c 100644 --- a/src/main/java/org/traccar/protocol/AutoTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/AutoTrackProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AutoTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/AvemaProtocol.java b/src/main/java/org/traccar/protocol/AvemaProtocol.java index b35a447ff..0eeee41b8 100644 --- a/src/main/java/org/traccar/protocol/AvemaProtocol.java +++ b/src/main/java/org/traccar/protocol/AvemaProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class AvemaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Avl301Protocol.java b/src/main/java/org/traccar/protocol/Avl301Protocol.java index c4a0affdc..452bc1501 100644 --- a/src/main/java/org/traccar/protocol/Avl301Protocol.java +++ b/src/main/java/org/traccar/protocol/Avl301Protocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Avl301Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/B2316Protocol.java b/src/main/java/org/traccar/protocol/B2316Protocol.java index 582be0b56..e0a6821d8 100644 --- a/src/main/java/org/traccar/protocol/B2316Protocol.java +++ b/src/main/java/org/traccar/protocol/B2316Protocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class B2316Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java b/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java index 635806b2d..b0a5411f7 100644 --- a/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java @@ -24,9 +24,9 @@ import org.traccar.model.Network; import org.traccar.model.Position; import org.traccar.model.WifiAccessPoint; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.util.Date; diff --git a/src/main/java/org/traccar/protocol/BceProtocol.java b/src/main/java/org/traccar/protocol/BceProtocol.java index 31fb1bd83..5e1c10abc 100644 --- a/src/main/java/org/traccar/protocol/BceProtocol.java +++ b/src/main/java/org/traccar/protocol/BceProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class BceProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/BlackKiteProtocol.java b/src/main/java/org/traccar/protocol/BlackKiteProtocol.java index 3859a9273..d584af5a1 100644 --- a/src/main/java/org/traccar/protocol/BlackKiteProtocol.java +++ b/src/main/java/org/traccar/protocol/BlackKiteProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class BlackKiteProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/BlueProtocol.java b/src/main/java/org/traccar/protocol/BlueProtocol.java index da195f438..821111ad7 100644 --- a/src/main/java/org/traccar/protocol/BlueProtocol.java +++ b/src/main/java/org/traccar/protocol/BlueProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class BlueProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/BoxProtocol.java b/src/main/java/org/traccar/protocol/BoxProtocol.java index dc6852d50..ac1ba7cae 100644 --- a/src/main/java/org/traccar/protocol/BoxProtocol.java +++ b/src/main/java/org/traccar/protocol/BoxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class BoxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/BstplProtocol.java b/src/main/java/org/traccar/protocol/BstplProtocol.java index dde14a2ca..ccedcf3d9 100644 --- a/src/main/java/org/traccar/protocol/BstplProtocol.java +++ b/src/main/java/org/traccar/protocol/BstplProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class BstplProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/C2stekProtocol.java b/src/main/java/org/traccar/protocol/C2stekProtocol.java index 5cd8ef4fd..5370ea762 100644 --- a/src/main/java/org/traccar/protocol/C2stekProtocol.java +++ b/src/main/java/org/traccar/protocol/C2stekProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class C2stekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CalAmpProtocol.java b/src/main/java/org/traccar/protocol/CalAmpProtocol.java index d67308cf2..06df6e196 100644 --- a/src/main/java/org/traccar/protocol/CalAmpProtocol.java +++ b/src/main/java/org/traccar/protocol/CalAmpProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CalAmpProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CarTrackProtocol.java b/src/main/java/org/traccar/protocol/CarTrackProtocol.java index 0538aad72..366f32034 100644 --- a/src/main/java/org/traccar/protocol/CarTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/CarTrackProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CarTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CarcellProtocol.java b/src/main/java/org/traccar/protocol/CarcellProtocol.java index 832d9bb2d..7ae8159d5 100644 --- a/src/main/java/org/traccar/protocol/CarcellProtocol.java +++ b/src/main/java/org/traccar/protocol/CarcellProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CarcellProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CarscopProtocol.java b/src/main/java/org/traccar/protocol/CarscopProtocol.java index a4413af28..e904c01c5 100644 --- a/src/main/java/org/traccar/protocol/CarscopProtocol.java +++ b/src/main/java/org/traccar/protocol/CarscopProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CarscopProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CastelProtocol.java b/src/main/java/org/traccar/protocol/CastelProtocol.java index 9323b1503..74a9e9ca1 100644 --- a/src/main/java/org/traccar/protocol/CastelProtocol.java +++ b/src/main/java/org/traccar/protocol/CastelProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import org.traccar.model.Command; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CastelProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java index 4aa65245b..b076b9f66 100644 --- a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java @@ -16,7 +16,6 @@ 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; @@ -284,15 +283,27 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder { case 0x0C: position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); break; + case 0x0D: + position.set(Position.KEY_ALARM, Position.ALARM_FATIGUE_DRIVING); + break; case 0x0E: position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); break; + case 0x11: + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); + break; + case 0x12: + position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING); + break; case 0x16: position.set(Position.KEY_IGNITION, true); break; case 0x17: position.set(Position.KEY_IGNITION, false); break; + case 0x1C: + position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); + break; default: break; } @@ -359,9 +370,9 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder { int alarmCount = buf.readUnsignedByte(); for (int i = 0; i < alarmCount; i++) { if (buf.readUnsignedByte() != 0) { - int alarm = buf.readUnsignedByte(); + int event = buf.readUnsignedByte(); for (Position p : positions) { - decodeAlarm(p, alarm); + decodeAlarm(p, event); } buf.readUnsignedShortLE(); // description buf.readUnsignedShortLE(); // threshold @@ -421,12 +432,26 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder { return position; case MSG_SC_DTCS_PASSENGER: + case MSG_SC_DTCS_COMMERCIAL: position = createPosition(deviceSession); decodeStat(position, buf); buf.readUnsignedByte(); // flag - position.add(ObdDecoder.decodeCodes(ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte())))); + + count = buf.readUnsignedByte(); + StringBuilder codes = new StringBuilder(); + for (int i = 0; i < count; i++) { + if (type == MSG_SC_DTCS_COMMERCIAL) { + codes.append(ObdDecoder.decodeCode(buf.readUnsignedShortLE())); + buf.readUnsignedByte(); // attribute + buf.readUnsignedByte(); // occurrence + } else { + codes.append(ObdDecoder.decodeCode(buf.readUnsignedShortLE())); + } + codes.append(' '); + } + position.set(Position.KEY_DTCS, codes.toString().trim()); return position; diff --git a/src/main/java/org/traccar/protocol/CautelaProtocol.java b/src/main/java/org/traccar/protocol/CautelaProtocol.java index d0ca35ef1..067345f49 100644 --- a/src/main/java/org/traccar/protocol/CautelaProtocol.java +++ b/src/main/java/org/traccar/protocol/CautelaProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CautelaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CellocatorProtocol.java b/src/main/java/org/traccar/protocol/CellocatorProtocol.java index 3287928c7..e3325c8b7 100644 --- a/src/main/java/org/traccar/protocol/CellocatorProtocol.java +++ b/src/main/java/org/traccar/protocol/CellocatorProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CellocatorProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CguardProtocol.java b/src/main/java/org/traccar/protocol/CguardProtocol.java index caf0aad42..c0fc9582a 100644 --- a/src/main/java/org/traccar/protocol/CguardProtocol.java +++ b/src/main/java/org/traccar/protocol/CguardProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CguardProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CityeasyProtocol.java b/src/main/java/org/traccar/protocol/CityeasyProtocol.java index 9656b284b..60ed5d135 100644 --- a/src/main/java/org/traccar/protocol/CityeasyProtocol.java +++ b/src/main/java/org/traccar/protocol/CityeasyProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CityeasyProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ContinentalProtocol.java b/src/main/java/org/traccar/protocol/ContinentalProtocol.java index 06e93d79d..9567374fd 100644 --- a/src/main/java/org/traccar/protocol/ContinentalProtocol.java +++ b/src/main/java/org/traccar/protocol/ContinentalProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ContinentalProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/CradlepointProtocol.java b/src/main/java/org/traccar/protocol/CradlepointProtocol.java index 7f201a31d..220db0747 100644 --- a/src/main/java/org/traccar/protocol/CradlepointProtocol.java +++ b/src/main/java/org/traccar/protocol/CradlepointProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class CradlepointProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DingtekProtocol.java b/src/main/java/org/traccar/protocol/DingtekProtocol.java index e9466b7e8..ab3e32fdb 100644 --- a/src/main/java/org/traccar/protocol/DingtekProtocol.java +++ b/src/main/java/org/traccar/protocol/DingtekProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DingtekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DishaProtocol.java b/src/main/java/org/traccar/protocol/DishaProtocol.java index f83b8349a..0a582731d 100644 --- a/src/main/java/org/traccar/protocol/DishaProtocol.java +++ b/src/main/java/org/traccar/protocol/DishaProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DishaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DmtHttpProtocol.java b/src/main/java/org/traccar/protocol/DmtHttpProtocol.java index 0dab26cda..d15bfa1ca 100644 --- a/src/main/java/org/traccar/protocol/DmtHttpProtocol.java +++ b/src/main/java/org/traccar/protocol/DmtHttpProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DmtHttpProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java b/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java index 807850778..c2e617a2a 100644 --- a/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java @@ -25,9 +25,9 @@ import org.traccar.helper.BitUtil; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/DmtProtocol.java b/src/main/java/org/traccar/protocol/DmtProtocol.java index de56c9372..e89920cd3 100644 --- a/src/main/java/org/traccar/protocol/DmtProtocol.java +++ b/src/main/java/org/traccar/protocol/DmtProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DmtProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DolphinProtocol.java b/src/main/java/org/traccar/protocol/DolphinProtocol.java index ed627be78..e2acce7dd 100644 --- a/src/main/java/org/traccar/protocol/DolphinProtocol.java +++ b/src/main/java/org/traccar/protocol/DolphinProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DolphinProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DraginoProtocol.java b/src/main/java/org/traccar/protocol/DraginoProtocol.java new file mode 100644 index 000000000..d33efe2ad --- /dev/null +++ b/src/main/java/org/traccar/protocol/DraginoProtocol.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class DraginoProtocol extends BaseProtocol { + + @Inject + public DraginoProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(65535)); + pipeline.addLast(new DraginoProtocolDecoder(DraginoProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/DraginoProtocolDecoder.java b/src/main/java/org/traccar/protocol/DraginoProtocolDecoder.java new file mode 100644 index 000000000..5f576d723 --- /dev/null +++ b/src/main/java/org/traccar/protocol/DraginoProtocolDecoder.java @@ -0,0 +1,78 @@ +/* + * Copyright 2023 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.helper.DateUtil; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.io.StringReader; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; + +public class DraginoProtocolDecoder extends BaseHttpProtocolDecoder { + + public DraginoProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + String content = request.content().toString(StandardCharsets.UTF_8); + JsonObject json = Json.createReader(new StringReader(content)).readObject(); + + String deviceId = json.getJsonObject("end_device_ids").getString("device_id"); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, deviceId); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + + JsonObject message = json.getJsonObject("uplink_message"); + JsonObject decoded = message.getJsonObject("decoded_payload"); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(DateUtil.parseDate(message.getString("received_at"))); + + position.setValid(true); + position.setLatitude(decoded.getJsonNumber("Latitude").doubleValue()); + position.setLongitude(decoded.getJsonNumber("Longitude").doubleValue()); + + position.set("humidity", decoded.getJsonNumber("Hum").doubleValue()); + position.set(Position.KEY_BATTERY, decoded.getJsonNumber("BatV").doubleValue()); + position.set(Position.PREFIX_TEMP + 1, decoded.getJsonNumber("Tem").doubleValue()); + + if (Boolean.parseBoolean(decoded.getString("ALARM_status"))) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } + + sendResponse(channel, HttpResponseStatus.OK); + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Dsf22Protocol.java b/src/main/java/org/traccar/protocol/Dsf22Protocol.java index 06c99b0f9..ad349a7ff 100644 --- a/src/main/java/org/traccar/protocol/Dsf22Protocol.java +++ b/src/main/java/org/traccar/protocol/Dsf22Protocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Dsf22Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DualcamProtocol.java b/src/main/java/org/traccar/protocol/DualcamProtocol.java index 363a2c5d9..4725cb180 100644 --- a/src/main/java/org/traccar/protocol/DualcamProtocol.java +++ b/src/main/java/org/traccar/protocol/DualcamProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DualcamProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java index d03f7648d..411e2b9d7 100644 --- a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 2023 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,13 +42,24 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_COMPLETE = 5; public static final int MSG_FILE_REQUEST = 8; public static final int MSG_INIT_REQUEST = 9; + public static final int MSG_PATH_REQUEST = 0x000C; + public static final int MSG_PATH_RESPONSE = 0x000D; + private String model; private String uniqueId; - private int packetCount; - private int currentPacket; + private int dataSize; + private int dataCurrent; private boolean video; private ByteBuf media; + private boolean isPacketData() { + if (model == null) { + return dataSize < 8192; + } else { + return !"DSM".equals(model); + } + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -57,15 +68,21 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { int type = buf.readUnsignedShort(); + DeviceSession deviceSession; switch (type) { case MSG_INIT: buf.readUnsignedShort(); // protocol id uniqueId = String.valueOf(buf.readLong()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, uniqueId); + deviceSession = getDeviceSession(channel, remoteAddress, uniqueId); long settings = buf.readUnsignedInt(); if (channel != null && deviceSession != null) { + model = getDeviceModel(deviceSession); ByteBuf response = Unpooled.buffer(); - if (BitUtil.between(settings, 26, 30) > 0) { + if (BitUtil.check(settings, 25)) { + response.writeShort(MSG_PATH_REQUEST); + response.writeShort(2); + response.writeShort(0); + } else if (BitUtil.between(settings, 26, 30) > 0) { response.writeShort(MSG_FILE_REQUEST); String file; if (BitUtil.check(settings, 26)) { @@ -91,21 +108,29 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { break; case MSG_START: buf.readUnsignedShort(); // length - packetCount = buf.readInt(); - currentPacket = 1; + dataSize = buf.readInt(); + dataCurrent = isPacketData() ? 1 : 0; media = Unpooled.buffer(); if (channel != null) { ByteBuf response = Unpooled.buffer(); response.writeShort(MSG_RESUME); response.writeShort(4); - response.writeInt(currentPacket); + response.writeInt(dataCurrent); channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } break; case MSG_DATA: - buf.readUnsignedShort(); // length - media.writeBytes(buf, buf.readableBytes() - 2); - if (currentPacket == packetCount) { + int length = buf.readUnsignedShort() - 2; + media.writeBytes(buf, length); + boolean finished; + if (isPacketData()) { + finished = dataCurrent == dataSize; + dataCurrent += 1; + } else { + finished = dataCurrent + length == dataSize; + dataCurrent += length; + } + if (finished) { deviceSession = getDeviceSession(channel, remoteAddress); Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); @@ -126,8 +151,16 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder { channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } return position; - } else { - currentPacket += 1; + } + break; + case MSG_PATH_RESPONSE: + String file = buf.readCharSequence(buf.readUnsignedShort(), StandardCharsets.US_ASCII).toString(); + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeShort(MSG_FILE_REQUEST); + response.writeShort(file.length()); + response.writeCharSequence(file, StandardCharsets.US_ASCII); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } break; default: diff --git a/src/main/java/org/traccar/protocol/DwayProtocol.java b/src/main/java/org/traccar/protocol/DwayProtocol.java index 1096c945c..2ba1cf5f1 100644 --- a/src/main/java/org/traccar/protocol/DwayProtocol.java +++ b/src/main/java/org/traccar/protocol/DwayProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class DwayProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EasyTrackProtocol.java b/src/main/java/org/traccar/protocol/EasyTrackProtocol.java index 39aa61580..25d4ef9a0 100644 --- a/src/main/java/org/traccar/protocol/EasyTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/EasyTrackProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EasyTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java index 805cf1197..b10ff4c64 100644 --- a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2023 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. @@ -79,26 +79,45 @@ public class EasyTrackProtocolDecoder extends BaseProtocolDecoder { .any() .compile(); + private static final Pattern PATTERN_OBD = new PatternBuilder() + .text("*").expression("..,") // manufacturer + .number("(d+),") // imei + .text("OB,") // command + .text("BD$") + .number("V(d+.d);") // battery + .number("R(d+);") // rpm + .number("S(d+);") // speed + .number("P(d+.d);") // throttle + .number("O(d+.d);") // engine load + .number("C(d+);") // coolant temperature + .number("L(d+.d);") // fuel level + .number("[XY][MH]d+.d+;") + .number("M(d+);") // mileage + .number("F(d+.d+);") // fuel consumption + .number("T(d+);") // engine time + .any() + .compile(); + private String decodeAlarm(long status) { - if ((status & 0x02000000) != 0) { + if ((status & 0x02000000L) != 0) { return Position.ALARM_GEOFENCE_ENTER; } - if ((status & 0x04000000) != 0) { + if ((status & 0x04000000L) != 0) { return Position.ALARM_GEOFENCE_EXIT; } - if ((status & 0x08000000) != 0) { + if ((status & 0x08000000L) != 0) { return Position.ALARM_LOW_BATTERY; } - if ((status & 0x20000000) != 0) { + if ((status & 0x20000000L) != 0) { return Position.ALARM_VIBRATION; } - if ((status & 0x80000000) != 0) { + if ((status & 0x80000000L) != 0) { return Position.ALARM_OVERSPEED; } - if ((status & 0x00010000) != 0) { + if ((status & 0x00010000L) != 0) { return Position.ALARM_SOS; } - if ((status & 0x00040000) != 0) { + if ((status & 0x00040000L) != 0) { return Position.ALARM_POWER_CUT; } return null; @@ -115,7 +134,9 @@ public class EasyTrackProtocolDecoder extends BaseProtocolDecoder { channel.writeAndFlush(new NetworkMessage(sentence + "#", remoteAddress)); } - if (type.equals("JZ")) { + if (type.equals("OB")) { + return decodeObd(channel, remoteAddress, sentence); + } else if (type.equals("JZ")) { return decodeCell(channel, remoteAddress, sentence); } else { return decodeLocation(channel, remoteAddress, sentence); @@ -219,4 +240,35 @@ public class EasyTrackProtocolDecoder extends BaseProtocolDecoder { return position; } + private Position decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_OBD, 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_RPM, parser.nextInt()); + position.set(Position.KEY_OBD_SPEED, parser.nextInt()); + position.set(Position.KEY_THROTTLE, parser.nextDouble()); + position.set(Position.KEY_ENGINE_LOAD, parser.nextDouble()); + position.set(Position.KEY_COOLANT_TEMP, parser.nextInt()); + position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble()); + position.set(Position.KEY_ODOMETER, parser.nextInt()); + position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextDouble()); + position.set(Position.KEY_HOURS, parser.nextInt()); + + return position; + } + } diff --git a/src/main/java/org/traccar/protocol/EelinkProtocol.java b/src/main/java/org/traccar/protocol/EelinkProtocol.java index 35fd4fe65..2a3c0bd15 100644 --- a/src/main/java/org/traccar/protocol/EelinkProtocol.java +++ b/src/main/java/org/traccar/protocol/EelinkProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EelinkProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java index cb0e10042..db1b365c3 100644 --- a/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java @@ -314,7 +314,7 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder { } if (buf.readableBytes() >= 12) { - position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort() / 256.0); + position.set(Position.PREFIX_TEMP + 1, buf.readShort() / 256.0); position.set("humidity", buf.readUnsignedShort() * 0.1); position.set("illuminance", buf.readUnsignedInt() / 256.0); position.set("co2", buf.readUnsignedInt()); diff --git a/src/main/java/org/traccar/protocol/EgtsProtocol.java b/src/main/java/org/traccar/protocol/EgtsProtocol.java index f257271d4..5450d9f01 100644 --- a/src/main/java/org/traccar/protocol/EgtsProtocol.java +++ b/src/main/java/org/traccar/protocol/EgtsProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EgtsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EnforaProtocol.java b/src/main/java/org/traccar/protocol/EnforaProtocol.java index ebde56f70..3b796db25 100644 --- a/src/main/java/org/traccar/protocol/EnforaProtocol.java +++ b/src/main/java/org/traccar/protocol/EnforaProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EnforaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EnnfuProtocol.java b/src/main/java/org/traccar/protocol/EnnfuProtocol.java index e326481fa..a3ff943fa 100644 --- a/src/main/java/org/traccar/protocol/EnnfuProtocol.java +++ b/src/main/java/org/traccar/protocol/EnnfuProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EnnfuProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EnvotechProtocol.java b/src/main/java/org/traccar/protocol/EnvotechProtocol.java index dffa1c991..e432ac07c 100644 --- a/src/main/java/org/traccar/protocol/EnvotechProtocol.java +++ b/src/main/java/org/traccar/protocol/EnvotechProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EnvotechProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EsealProtocol.java b/src/main/java/org/traccar/protocol/EsealProtocol.java index 0ed80dc6f..eae4cf2aa 100644 --- a/src/main/java/org/traccar/protocol/EsealProtocol.java +++ b/src/main/java/org/traccar/protocol/EsealProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EsealProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/EskyProtocol.java b/src/main/java/org/traccar/protocol/EskyProtocol.java index cb2f59dc8..002e268ba 100644 --- a/src/main/java/org/traccar/protocol/EskyProtocol.java +++ b/src/main/java/org/traccar/protocol/EskyProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class EskyProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ExtremTracProtocol.java b/src/main/java/org/traccar/protocol/ExtremTracProtocol.java index ffc941b69..23a993fe4 100644 --- a/src/main/java/org/traccar/protocol/ExtremTracProtocol.java +++ b/src/main/java/org/traccar/protocol/ExtremTracProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ExtremTracProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocol.java b/src/main/java/org/traccar/protocol/FifotrackProtocol.java index fd2beaabb..e98ad84cc 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocol.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FifotrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java index a9d77b46e..59019830f 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -64,7 +64,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { .number("(d+),") // course .number("(-?d+),") // altitude .number("(d+),") // odometer - .number("d+,") // runtime + .number("(d+),") // engine hours .number("(x+),") // status .number("(x+)?,") // input .number("(x+)?,") // output @@ -183,6 +183,8 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { case 30: case 32: return Position.ALARM_JAMMING; + case 31: + return Position.ALARM_FALL_DOWN; case 33: return Position.ALARM_GEOFENCE_EXIT; case 34: @@ -192,6 +194,10 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { case 40: case 41: return Position.ALARM_TEMPERATURE; + case 53: + return Position.ALARM_POWER_ON; + case 54: + return Position.ALARM_POWER_OFF; default: return null; } @@ -235,13 +241,15 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { position.setValid(parser.next().equals("A")); position.setFixTime(position.getDeviceTime()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + position.set(Position.KEY_SATELLITES, parser.nextInt()); position.setLatitude(parser.nextDouble()); position.setLongitude(parser.nextDouble()); } else { + getLastLocation(position, position.getDeviceTime()); + String[] points = parser.next().split("\\|"); for (String point : points) { String[] wifi = point.split(":"); @@ -290,6 +298,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { position.setAltitude(parser.nextInt()); position.set(Position.KEY_ODOMETER, parser.nextLong()); + position.set(Position.KEY_HOURS, parser.nextLong() * 1000); long status = parser.nextHexLong(); position.set(Position.KEY_RSSI, BitUtil.between(status, 3, 8)); @@ -308,11 +317,11 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { } if (parser.hasNext()) { - String rfid = parser.next(); - if (rfid.matches("\\p{XDigit}+")) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(Integer.parseInt(rfid, 16))); + String value = parser.next(); + if (value.matches("\\p{XDigit}+")) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(Integer.parseInt(value, 16))); } else { - position.set("driverLicense", rfid); + position.set(Position.KEY_CARD, value); } } diff --git a/src/main/java/org/traccar/protocol/FleetGuideProtocol.java b/src/main/java/org/traccar/protocol/FleetGuideProtocol.java new file mode 100644 index 000000000..46611c25c --- /dev/null +++ b/src/main/java/org/traccar/protocol/FleetGuideProtocol.java @@ -0,0 +1,36 @@ +/* + * Copyright 2024 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 jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class FleetGuideProtocol extends BaseProtocol { + + @Inject + public FleetGuideProtocol(Config config) { + addServer(new TrackerServer(config, getName(), true) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new FleetGuideProtocolDecoder(FleetGuideProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java new file mode 100644 index 000000000..8f679525b --- /dev/null +++ b/src/main/java/org/traccar/protocol/FleetGuideProtocolDecoder.java @@ -0,0 +1,328 @@ +/* + * Copyright 2024 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.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Checksum; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.net.SocketAddress; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class FleetGuideProtocolDecoder extends BaseProtocolDecoder { + + public FleetGuideProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_EMPTY = 0; + public static final int MSG_SYNC_REQ = 1; + public static final int MSG_SYNC_ACK = 2; + public static final int MSG_DATA_R_ACK = 3; + public static final int MSG_DATA_N_ACK = 4; + public static final int MSG_REP_R_ACK = 5; + public static final int MSG_REP_N_ACK = 6; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // signature + int options = buf.readUnsignedShortLE(); + int length = BitUtil.to(options, 11); + + DeviceSession deviceSession; + Long deviceId; + if (BitUtil.check(options, 11)) { + deviceId = buf.readUnsignedIntLE(); + deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); + } else { + deviceId = null; + deviceSession = getDeviceSession(channel, remoteAddress); + } + if (deviceSession == null) { + return null; + } + + int type; + Integer index; + if (BitUtil.check(options, 12)) { + int value = buf.readUnsignedByte(); + type = BitUtil.to(value, 4); + index = BitUtil.from(value, 4); + } else { + type = 0; + index = null; + } + + if (type != MSG_DATA_N_ACK && type != MSG_REP_N_ACK) { + Integer responseType; + if (type == MSG_SYNC_REQ) { + responseType = MSG_SYNC_ACK; + } else { + responseType = null; + } + sendResponse(channel, remoteAddress, deviceId, responseType, index); + } + + if (BitUtil.check(options, 13)) { + buf.readUnsignedShortLE(); // acknowledgement + } + + ByteBuf data; + if (BitUtil.check(options, 14)) { + data = decompress(buf.readSlice(length)); + } else { + data = buf.readRetainedSlice(length); + } + + List<Position> positions = new LinkedList<>(); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + while (data.isReadable()) { + + int recordHeader = data.readUnsignedShortLE(); + int recordLength = BitUtil.to(recordHeader, 10); + int recordType = BitUtil.from(recordHeader, 10); + int recordEndIndex = data.readerIndex() + recordLength; + + if (recordType == 0 && position.getDeviceTime() != null) { + processPosition(positions, position); + position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + } + + switch (recordType) { + case 0: + position.setTime(new Date((data.readUnsignedIntLE() + 1262304000) * 1000)); // since 2010-01-01 + break; + case 1: + position.setLatitude(data.readUnsignedIntLE() * 90.0 / 0xFFFFFFFFL); + position.setLongitude(data.readUnsignedIntLE() * 180.0 / 0xFFFFFFFFL); + int speed = data.readUnsignedShortLE(); + position.setSpeed(UnitsConverter.knotsFromKph(BitUtil.to(speed, 14) * 0.1)); + if (BitUtil.check(speed, 14)) { + position.setLatitude(-position.getLatitude()); + } + if (BitUtil.check(speed, 15)) { + position.setLongitude(-position.getLongitude()); + } + int course = data.readUnsignedShortLE(); + position.setSpeed(BitUtil.to(course, 9)); + int motion = BitUtil.between(course, 9, 11); + if (motion > 0) { + position.set(Position.KEY_MOTION, motion == 1); + } + position.set(Position.KEY_SATELLITES, BitUtil.from(course, 11)); + int altitude = data.readUnsignedShortLE(); + position.setAltitude(BitUtil.to(altitude, 14)); + if (BitUtil.check(altitude, 14)) { + position.setAltitude(-position.getAltitude()); + } + break; + case 3: + int powerLow = data.readUnsignedByte(); + int powerFlags = data.readUnsignedByte(); + int batteryHigh = data.readUnsignedByte(); + position.set(Position.KEY_POWER, (powerLow + (BitUtil.to(powerFlags, 5) << 8)) * 0.01); + position.set(Position.KEY_IGNITION, BitUtil.check(powerFlags, 5)); + position.set(Position.KEY_BATTERY, (BitUtil.from(powerFlags, 6) + (batteryHigh << 2)) * 0.01); + if (recordLength >= 4) { + int extraFlags = data.readUnsignedByte(); + if (BitUtil.check(extraFlags, 0)) { + position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); + } + if (BitUtil.check(extraFlags, 1)) { + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + } + } + break; + case 6: + position.set(Position.KEY_INPUT, data.readUnsignedByte()); + break; + case 7: + position.set(Position.KEY_OUTPUT, data.readUnsignedByte()); + break; + case 8: + int adcMask = data.readUnsignedByte(); + for (int i = 0; i < 8; i++) { + if (BitUtil.check(adcMask, i)) { + position.set(Position.PREFIX_ADC + (i + 1), data.readUnsignedShortLE()); + } + } + break; + case 11: + int fuelMask = data.readUnsignedByte(); + for (int i = 1; i < 8; i++) { + if (BitUtil.check(fuelMask, i)) { + position.set("fuel" + i, data.readUnsignedShortLE()); + } + } + break; + case 12: + int fuelTempMask = data.readUnsignedByte(); + for (int i = 1; i < 8; i++) { + if (BitUtil.check(fuelTempMask, i)) { + position.set("fuelTemp" + i, (int) data.readByte()); + } + } + break; + case 13: + int tempMask = data.readUnsignedByte(); + for (int i = 0; i < 8; i++) { + if (BitUtil.check(tempMask, i)) { + position.set(Position.PREFIX_TEMP + (i + 1), data.readShortLE() * 0.01); + } + } + break; + case 18: + int sensorIndex = data.readUnsignedByte(); + switch (recordLength - 1) { + case 1: + position.set("sensor" + sensorIndex, data.readUnsignedByte()); + break; + case 2: + position.set("sensor" + sensorIndex, data.readUnsignedShortLE()); + break; + case 4: + position.set("sensor" + sensorIndex, data.readUnsignedIntLE()); + break; + default: + break; + } + break; + default: + break; + } + + data.readerIndex(recordEndIndex); + + } + + processPosition(positions, position); + + data.release(); + + return positions.isEmpty() ? null : positions; + } + + private void processPosition(List<Position> positions, Position position) { + if (!position.getAttributes().isEmpty()) { + if (position.getFixTime() == null) { + position.setTime(new Date()); + } + if (!position.getAttributes().containsKey(Position.KEY_SATELLITES)) { + getLastLocation(position, null); + } + positions.add(position); + } + } + + + private void sendResponse( + Channel channel, SocketAddress remoteAddress, Long deviceId, Integer type, Integer index) { + if (channel != null) { + + ByteBuf response = Unpooled.buffer(); + response.writeByte(0x53); // signature + + int options = 0; + if (deviceId != null) { + options |= 1 << 11; + } + if (type != null) { + options |= 1 << 12; + } + if (index != null) { + options |= 1 << 13; + } + response.writeShortLE(options); + + if (deviceId != null) { + response.writeIntLE(deviceId.intValue()); + } + if (type != null) { + response.writeByte(type); + } + if (index != null) { + int mask = (1 << (index + 1)) - 1; + response.writeShortLE(mask); + } + response.writeShortLE(Checksum.crc16( + Checksum.CRC16_CCITT_FALSE, response.nioBuffer(1, response.writerIndex() - 1))); + + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + private int readVarSize(ByteBuf buf) { + int b; + int y = 0; + do { + b = buf.readUnsignedByte(); + y = (y << 7) | (b & 0x0000007f); + } while ((b & 0x00000080) > 0); + + return y; + } + + private ByteBuf decompress(ByteBuf in) { + + ByteBuf out = Unpooled.buffer(); + + if (in.readableBytes() < 1) { + return out; + } + + int marker = in.readUnsignedByte(); + + do { + int symbol = in.readUnsignedByte(); + if (symbol == marker) { + if (in.getUnsignedByte(in.readerIndex()) == 0) { + out.writeByte(marker); + in.skipBytes(1); + } else { + int length = readVarSize(in); + int offset = readVarSize(in); + + for (int i = 0; i < length; i++) { + out.writeByte(out.getUnsignedByte(out.writerIndex() - offset)); + } + } + } else { + out.writeByte(symbol); + } + } while (in.isReadable()); + + return out; + } + +} diff --git a/src/main/java/org/traccar/protocol/FlespiProtocol.java b/src/main/java/org/traccar/protocol/FlespiProtocol.java index 374cf77e2..0d8448845 100644 --- a/src/main/java/org/traccar/protocol/FlespiProtocol.java +++ b/src/main/java/org/traccar/protocol/FlespiProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FlespiProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java index 6e6f9c700..ea076afd8 100644 --- a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java @@ -24,12 +24,12 @@ import org.traccar.Protocol; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonNumber; -import javax.json.JsonObject; -import javax.json.JsonString; -import javax.json.JsonValue; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonNumber; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; @@ -125,12 +125,13 @@ public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder { position.set(Position.KEY_PDOP, ((JsonNumber) value).doubleValue()); return true; case "din": + position.set(Position.KEY_INPUT, ((JsonNumber) value).intValue()); + return true; case "dout": - if (name.equals("din")) { - position.set(Position.KEY_INPUT, ((JsonNumber) value).intValue()); - } else { - position.set(Position.KEY_OUTPUT, ((JsonNumber) value).intValue()); - } + position.set(Position.KEY_OUTPUT, ((JsonNumber) value).intValue()); + return true; + case "report.reason": + position.set(Position.KEY_EVENT, ((JsonNumber) value).intValue()); return true; case "gps.vehicle.mileage": position.set(Position.KEY_ODOMETER, ((JsonNumber) value).doubleValue()); @@ -141,6 +142,9 @@ public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder { case "battery.voltage": position.set(Position.KEY_BATTERY, ((JsonNumber) value).doubleValue()); return true; + case "battery.level": + position.set(Position.KEY_BATTERY_LEVEL, ((JsonNumber) value).intValue()); + return true; case "fuel.level": case "can.fuel.level": position.set(Position.KEY_FUEL_LEVEL, ((JsonNumber) value).doubleValue()); diff --git a/src/main/java/org/traccar/protocol/FlexApiProtocol.java b/src/main/java/org/traccar/protocol/FlexApiProtocol.java index 088072d2d..b2e3f5d00 100644 --- a/src/main/java/org/traccar/protocol/FlexApiProtocol.java +++ b/src/main/java/org/traccar/protocol/FlexApiProtocol.java @@ -24,7 +24,7 @@ import org.traccar.config.Config; import java.nio.charset.StandardCharsets; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FlexApiProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java index 2dec44e64..fb76673ca 100644 --- a/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java @@ -23,8 +23,8 @@ import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.util.Date; diff --git a/src/main/java/org/traccar/protocol/FlexCommProtocol.java b/src/main/java/org/traccar/protocol/FlexCommProtocol.java index 5397156cb..293b9b12b 100644 --- a/src/main/java/org/traccar/protocol/FlexCommProtocol.java +++ b/src/main/java/org/traccar/protocol/FlexCommProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FlexCommProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FlexibleReportProtocol.java b/src/main/java/org/traccar/protocol/FlexibleReportProtocol.java index 61e315af9..a16e61458 100644 --- a/src/main/java/org/traccar/protocol/FlexibleReportProtocol.java +++ b/src/main/java/org/traccar/protocol/FlexibleReportProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FlexibleReportProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FlextrackProtocol.java b/src/main/java/org/traccar/protocol/FlextrackProtocol.java index ebac8b4de..b6353de9d 100644 --- a/src/main/java/org/traccar/protocol/FlextrackProtocol.java +++ b/src/main/java/org/traccar/protocol/FlextrackProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FlextrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FoxProtocol.java b/src/main/java/org/traccar/protocol/FoxProtocol.java index fa45b3817..edb496f11 100644 --- a/src/main/java/org/traccar/protocol/FoxProtocol.java +++ b/src/main/java/org/traccar/protocol/FoxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FoxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FreedomProtocol.java b/src/main/java/org/traccar/protocol/FreedomProtocol.java index dac117c04..87404094a 100644 --- a/src/main/java/org/traccar/protocol/FreedomProtocol.java +++ b/src/main/java/org/traccar/protocol/FreedomProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FreedomProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FreematicsProtocol.java b/src/main/java/org/traccar/protocol/FreematicsProtocol.java index dce4994ab..c4076f330 100644 --- a/src/main/java/org/traccar/protocol/FreematicsProtocol.java +++ b/src/main/java/org/traccar/protocol/FreematicsProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FreematicsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java b/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java index 4e5200f37..d0402cc94 100644 --- a/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java @@ -153,7 +153,7 @@ public class FreematicsProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_RSSI, Integer.parseInt(value)); break; case 0x82: - position.set(Position.KEY_DEVICE_TEMP, Integer.parseInt(value) * 0.1); + position.set(Position.KEY_DEVICE_TEMP, Double.parseDouble(value) * 0.1); break; case 0x104: position.set(Position.KEY_ENGINE_LOAD, Integer.parseInt(value)); @@ -165,7 +165,7 @@ public class FreematicsProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_RPM, Integer.parseInt(value)); break; case 0x10d: - position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(Integer.parseInt(value))); + position.set(Position.KEY_OBD_SPEED, Integer.parseInt(value)); break; case 0x111: position.set(Position.KEY_THROTTLE, Integer.parseInt(value)); diff --git a/src/main/java/org/traccar/protocol/FutureWayProtocol.java b/src/main/java/org/traccar/protocol/FutureWayProtocol.java index 715dd3c9c..20586bede 100644 --- a/src/main/java/org/traccar/protocol/FutureWayProtocol.java +++ b/src/main/java/org/traccar/protocol/FutureWayProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class FutureWayProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/G1rusProtocol.java b/src/main/java/org/traccar/protocol/G1rusProtocol.java index f1823762d..b3904b357 100644 --- a/src/main/java/org/traccar/protocol/G1rusProtocol.java +++ b/src/main/java/org/traccar/protocol/G1rusProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class G1rusProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java b/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java index c23d26c83..d90e48287 100644 --- a/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2023 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,7 +22,7 @@ import org.traccar.BaseFrameDecoder; public class GalileoFrameDecoder extends BaseFrameDecoder { - private static final int MESSAGE_MINIMUM_LENGTH = 5; + private static final int MESSAGE_MINIMUM_LENGTH = 6; @Override protected Object decode( @@ -32,9 +32,15 @@ public class GalileoFrameDecoder extends BaseFrameDecoder { return null; } - int length = buf.getUnsignedShortLE(buf.readerIndex() + 1) & 0x7fff; - if (buf.readableBytes() >= (length + MESSAGE_MINIMUM_LENGTH)) { - return buf.readRetainedSlice(length + MESSAGE_MINIMUM_LENGTH); + int length; + if (buf.getByte(buf.readerIndex()) == 0x01 && buf.getUnsignedMedium(buf.readerIndex() + 3) == 0x01001c) { + length = 3 + buf.getUnsignedShort(buf.readerIndex() + 1); + } else { + length = 5 + (buf.getUnsignedShortLE(buf.readerIndex() + 1) & 0x7fff); + } + + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); } return null; diff --git a/src/main/java/org/traccar/protocol/GalileoProtocol.java b/src/main/java/org/traccar/protocol/GalileoProtocol.java index 90e95574a..95ce4edde 100644 --- a/src/main/java/org/traccar/protocol/GalileoProtocol.java +++ b/src/main/java/org/traccar/protocol/GalileoProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GalileoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java index 7341b69a3..d29ed9ce7 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocol.java +++ b/src/main/java/org/traccar/protocol/GatorProtocol.java @@ -20,17 +20,25 @@ import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; +import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GatorProtocol extends BaseProtocol { @Inject public GatorProtocol(Config config) { + setSupportedDataCommands( + Command.TYPE_POSITION_SINGLE, + Command.TYPE_ENGINE_RESUME, + Command.TYPE_ENGINE_STOP, + Command.TYPE_SET_SPEED_LIMIT, + Command.TYPE_SET_ODOMETER); addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2)); + pipeline.addLast(new GatorProtocolEncoder(GatorProtocol.this)); pipeline.addLast(new GatorProtocolDecoder(GatorProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java index 644caee81..a9c620090 100644 --- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -37,6 +37,11 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder { } public static final int MSG_HEARTBEAT = 0x21; + public static final int MSG_POSITION_REQUEST = 0x30; + public static final int MSG_OVERSPEED_ALARM = 0x3F; + public static final int MSG_RESET_MILEAGE = 0x6B; + public static final int MSG_RESTORE_OIL_DUCT = 0x38; + public static final int MSG_CLOSE_OIL_DUCT = 0x39; public static final int MSG_POSITION_DATA = 0x80; public static final int MSG_ROLLCALL_RESPONSE = 0x81; public static final int MSG_ALARM_DATA = 0x82; diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java new file mode 100644 index 000000000..6c6b9a54a --- /dev/null +++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java @@ -0,0 +1,93 @@ +/* + * Copyright 2023 Hossain Mohammad Seym (seym45@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.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; + +public class GatorProtocolEncoder extends BaseProtocolEncoder { + + public GatorProtocolEncoder(Protocol protocol) { + super(protocol); + } + + public ByteBuf encodeId(long deviceId) { + ByteBuf buf = Unpooled.buffer(); + + String id = getUniqueId(deviceId); + + int firstDigit = Integer.parseInt(id.substring(1, 3)) - 30; + + buf.writeByte(Integer.parseInt(id.substring(3, 5)) | (((firstDigit >> 3) & 1) << 7)); + buf.writeByte(Integer.parseInt(id.substring(5, 7)) | (((firstDigit >> 2) & 1) << 7)); + buf.writeByte(Integer.parseInt(id.substring(7, 9)) | (((firstDigit >> 1) & 1) << 7)); + buf.writeByte(Integer.parseInt(id.substring(9)) | ((firstDigit & 1) << 7)); + + return buf; + } + + private ByteBuf encodeContent(long deviceId, int type, ByteBuf content) { + ByteBuf buf = Unpooled.buffer(); + + buf.writeByte(0x24); + buf.writeByte(0x24); + buf.writeByte(type); + buf.writeByte(0x00); + + buf.writeByte(4 + 1 + (content != null ? content.readableBytes() : 0) + 1); // length + + ByteBuf pseudoIPAddress = encodeId(deviceId); + buf.writeBytes(pseudoIPAddress); + + if (content != null) { + buf.writeBytes(content); + } + + int checksum = Checksum.xor(buf.nioBuffer()); + buf.writeByte(checksum); + + buf.writeByte(0x0D); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + ByteBuf content = Unpooled.buffer(); + + switch (command.getType()) { + case Command.TYPE_POSITION_SINGLE: + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_REQUEST, null); + case Command.TYPE_ENGINE_STOP: + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_CLOSE_OIL_DUCT, null); + case Command.TYPE_ENGINE_RESUME: + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_RESTORE_OIL_DUCT, null); + case Command.TYPE_SET_SPEED_LIMIT: + content.writeByte(command.getInteger(Command.KEY_DATA)); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_RESET_MILEAGE, content); + case Command.TYPE_SET_ODOMETER: + content.writeShort(command.getInteger(Command.KEY_DATA)); + return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_OVERSPEED_ALARM, content); + default: + return null; + } + } +} diff --git a/src/main/java/org/traccar/protocol/GenxProtocol.java b/src/main/java/org/traccar/protocol/GenxProtocol.java index 97d8633a0..7e5a6a69e 100644 --- a/src/main/java/org/traccar/protocol/GenxProtocol.java +++ b/src/main/java/org/traccar/protocol/GenxProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GenxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gl100Protocol.java b/src/main/java/org/traccar/protocol/Gl100Protocol.java index e1748c9a0..fdd79648f 100644 --- a/src/main/java/org/traccar/protocol/Gl100Protocol.java +++ b/src/main/java/org/traccar/protocol/Gl100Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gl100Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gl200Protocol.java b/src/main/java/org/traccar/protocol/Gl200Protocol.java index c7b6a8e7c..e3ddbb46e 100644 --- a/src/main/java/org/traccar/protocol/Gl200Protocol.java +++ b/src/main/java/org/traccar/protocol/Gl200Protocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gl200Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java index a9736c9e7..9b4e05c35 100644 --- a/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java @@ -22,7 +22,7 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import org.traccar.Protocol; -import javax.inject.Inject; +import jakarta.inject.Inject; import java.net.SocketAddress; public class Gl200ProtocolDecoder extends BaseProtocolDecoder { diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 517499f02..2e5ffa8d6 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 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2024 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. @@ -15,12 +15,15 @@ */ 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.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.config.Keys; import org.traccar.helper.BitUtil; +import org.traccar.helper.DataConverter; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; import org.traccar.helper.UnitsConverter; @@ -28,15 +31,14 @@ import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; import org.traccar.model.WifiAccessPoint; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; +import org.traccar.session.DeviceSession; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.TimeZone; @@ -47,8 +49,12 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private boolean ignoreFixTime; + private final DateFormat dateFormat; + public Gl200TextProtocolDecoder(Protocol protocol) { super(protocol); + dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); } @Override @@ -56,21 +62,67 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { ignoreFixTime = getConfig().getBoolean(Keys.PROTOCOL_IGNORE_FIX_TIME.withPrefix(getProtocolName())); } - private static final Pattern PATTERN_ACK = new PatternBuilder() - .text("+ACK:GT") - .expression("...,") // type - .number("([0-9A-Z]{2}xxxx),") // protocol version - .number("(d{15}|x{14}),") // imei - .any().text(",") - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(xxxx)") // counter - .text("$").optional() - .compile(); + private String getDeviceModel(DeviceSession deviceSession, String value) { + String model = value.isEmpty() ? getDeviceModel(deviceSession) : value; + return model != null ? model.toUpperCase() : ""; + } + + private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) { + if (parser.matches()) { + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession != null) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + return position; + } + } + return null; + } + + private void decodeDeviceTime(Position position, Parser parser) { + if (parser.hasNext(6)) { + if (ignoreFixTime) { + position.setTime(parser.nextDateTime()); + } else { + position.setDeviceTime(parser.nextDateTime()); + } + } + } + + private Long parseHours(String hoursString) { + if (hoursString != null && !hoursString.isEmpty()) { + String[] hours = hoursString.split(":"); + return (Integer.parseInt(hours[0]) * 3600L + + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60L : 0) + + (hours.length > 2 ? Integer.parseInt(hours[2]) : 0)) * 1000; + } + return null; + } + + private Position decodeAck(Channel channel, SocketAddress remoteAddress, String[] values) throws ParseException { + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[2]); + if (deviceSession == null) { + return null; + } + if (values[0].equals("+ACK:GTHBD")) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage( + "+SACK:GTHBD," + values[1] + "," + values[values.length - 1] + "$", remoteAddress)); + } + } else { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + getLastLocation(position, dateFormat.parse(values[values.length - 2])); + position.setValid(false); + position.set(Position.KEY_RESULT, values[0]); + return position; + } + return null; + } private static final Pattern PATTERN_INF = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GTINF,") - .number("[0-9A-Z]{2}xxxx,") // protocol version + .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("(?:[0-9A-Z]{17},)?") // vin .expression("(?:[^,]+)?,") // device name @@ -109,374 +161,6 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .text("$").optional() .compile(); - private static final Pattern PATTERN_VER = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTVER,") - .number("[0-9A-Z]{2}xxxx,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .expression("([^,]*),") // device type - .number("(xxxx),") // firmware version - .number("(xxxx),") // hardware version - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(xxxx)") // counter - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_LOCATION = new PatternBuilder() - .number("(d{1,2}.?d?)?,") // hdop - .number("(d{1,3}.d)?,") // speed - .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 - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(d+)?,") // mcc - .number("(d+)?,") // mnc - .groupBegin() - .number("(d+),") // lac - .number("(d+),") // cid - .or() - .number("(x+)?,") // lac - .number("(x+)?,") // cid - .groupEnd() - .number("(?:d+|(d+.d))?,") // rssi / odometer - .compile(); - - private static final Pattern PATTERN_OBD = new PatternBuilder() - .text("+RESP:GTOBD,") - .number("[0-9A-Z]{2}xxxx,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("(?:[0-9A-Z]{17})?,") // vin - .expression("[^,]{0,20},") // device name - .expression("[01],") // report type - .number("x{1,8},") // report mask - .expression("(?:[0-9A-Z]{17})?,") // vin - .number("[01],") // obd connect - .number("(?:d{1,5})?,") // obd voltage - .number("(?:x{8})?,") // support pids - .number("(d{1,5})?,") // engine rpm - .number("(d{1,3})?,") // speed - .number("(-?d{1,3})?,") // coolant temp - .number("(d+.?d*|Inf|NaN)?,") // fuel consumption - .number("(d{1,5})?,") // dtcs cleared distance - .number("(?:d{1,5})?,") - .expression("([01])?,") // obd connect - .number("(d{1,3})?,") // number of dtcs - .number("(x*),") // dtcs - .number("(d{1,3})?,") // throttle - .number("(?:d{1,3})?,") // engine load - .number("(d{1,3})?,") // fuel level - .expression("(?:[0-9A],)?") // obd protocol - .number("(d+),") // odometer - .expression(PATTERN_LOCATION.pattern()) - .number("(d{1,7}.d)?,") // odometer - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_FRI = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("(?:([0-9A-Z]{17}),)?") // vin - .expression("[^,]*,") // device name - .number("(d+)?,") // power - .number("(d{1,2}),").optional() // report type - .number("d{1,2},").optional() // count - .number("d*,").optional() // reserved - .number("(d+),").optional() // battery - .expression("((?:") - .expression(PATTERN_LOCATION.pattern()) - .expression(")+)") - .groupBegin() - .number("d{1,2},,") - .number("(d{1,3}),") // battery - .number("[01],") // mode - .number("(?:[01])?,") // motion - .number("(?:-?d{1,2}.d)?,") // temperature - .or() - .number("(d{1,7}.d)?,") // odometer - .number("(d{5}:dd:dd)?,") // hour meter - .number("(x+)?,") // adc 1 - .number("(x+)?,") // adc 2 - .number("(d{1,3})?,") // battery - .number("(?:(xx)(xx)(xx))?,") // device status - .number("(d+)?,") // rpm - .number("(?:d+.?d*|Inf|NaN)?,") // fuel consumption - .number("(d+)?,") // fuel level - .or() - .number("(-?d),") // rssi - .number("(d{1,3}),") // battery - .or() - .number("(d{1,7}.d)?,").optional() // odometer - .number("(d{1,3})?,") // battery - .groupEnd() - .any() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_ERI = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTERI,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("(x{8}),") // mask - .number("(d+)?,") // power - .number("d{1,2},") // report type - .number("d{1,2},") // count - .expression("((?:") - .expression(PATTERN_LOCATION.pattern()) - .expression(")+)") - .groupBegin() - .number("(d{1,7}.d)?,") // odometer - .number("(d{5}:dd:dd)?,") // hour meter - .number("(x+)?,") // adc 1 - .number("(x+)?,").optional() // adc 2 - .groupBegin() - .number("(x+)?,") // adc 3 - .number("(xx),") // inputs - .number("(xx),") // outputs - .or() - .number("(d{1,3})?,") // battery - .number("(?:(xx)(xx)(xx))?,") // device status - .groupEnd() - .expression("(.*)") // additional data - .or() - .number("d*,,") - .number("(d+),") // battery - .any() - .groupEnd() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_IGN = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTIG[NF],") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("d+,") // ignition off duration - .expression(PATTERN_LOCATION.pattern()) - .number("(d{5}:dd:dd)?,") // hour meter - .number("(d{1,7}.d)?,") // odometer - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_LSW = new PatternBuilder() - .text("+RESP:").expression("GT[LT]SW,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("[01],") // type - .number("([01]),") // state - .expression(PATTERN_LOCATION.pattern()) - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_IDA = new PatternBuilder() - .text("+RESP:GTIDA,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,,") // device name - .number("([^,]+),") // rfid - .expression("[01],") // report type - .number("1,") // count - .expression(PATTERN_LOCATION.pattern()) - .number("(d+.d),") // odometer - .text(",,,,") - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_WIF = new PatternBuilder() - .text("+RESP:GTWIF,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("(d+),") // count - .number("((?:x{12},-?d+,,,,)+),,,,") // wifi - .number("(d{1,3}),") // battery - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_GSM = new PatternBuilder() - .text("+RESP:GTGSM,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("(?:STR|CTN|NMR|RTL),") // fix type - .expression("(.*)") // cells - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_PNA = new PatternBuilder() - .text("+RESP:GT").expression("P[NF]A,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_DAR = new PatternBuilder() - .text("+RESP:GTDAR,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("(d),") // warning type - .number("(d{1,2}),,,") // fatigue degree - .expression(PATTERN_LOCATION.pattern()) - .any() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("d*,") - .number("(x{1,2}),") // report type - .number("d{1,2},") // count - .number("d*,").optional() // reserved - .expression(PATTERN_LOCATION.pattern()) - .groupBegin() - .number("(?:(d{1,7}.d)|0)?,").optional() // odometer - .number("(d{1,3})?,") // battery - .or() - .number("(d{1,7}.d)?,") // odometer - .groupEnd() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)") // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_BASIC = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF)").text(":") - .expression("GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,").optional() // protocol version - .number("(d{15}|x{14}),") // imei - .any() - .text(",") - .number("(d{1,2})?,") // hdop - .number("(d{1,3}.d)?,") // speed - .number("(d{1,3})?,") // course - .number("(-?d{1,5}.d)?,") // altitude - .number("(-?d{1,3}.d{6})?,") // longitude - .number("(-?d{1,2}.d{6})?,") // latitude - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(x+),") // lac - .number("(x+),").optional(4) // cell - .any() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private Object decodeAck(Channel channel, SocketAddress remoteAddress, String sentence, String type) { - Parser parser = new Parser(PATTERN_ACK, sentence); - if (parser.matches()) { - String protocolVersion = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - if (type.equals("HBD")) { - if (channel != null) { - parser.skip(6); - channel.writeAndFlush(new NetworkMessage( - "+SACK:GTHBD," + protocolVersion + "," + parser.next() + "$", remoteAddress)); - } - } else { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - getLastLocation(position, parser.nextDateTime()); - position.setValid(false); - position.set(Position.KEY_RESULT, "Command " + type + " accepted"); - return position; - } - } - return null; - } - - private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) { - if (parser.matches()) { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession != null) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - return position; - } - } - return null; - } - - private void decodeDeviceTime(Position position, Parser parser) { - if (parser.hasNext(6)) { - if (ignoreFixTime) { - position.setTime(parser.nextDateTime()); - } else { - position.setDeviceTime(parser.nextDateTime()); - } - } - } - - private Long parseHours(String hoursString) { - if (hoursString != null) { - String[] hours = hoursString.split(":"); - return (long) (Integer.parseInt(hours[0]) * 3600 - + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60 : 0) - + (hours.length > 2 ? Integer.parseInt(hours[2]) : 0)) * 1000; - } - return null; - } - private Object decodeInf(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_INF, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -537,6 +221,20 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_VER = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GTVER,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .expression("([^,]*),") // device type + .number("(xxxx),") // firmware version + .number("(xxxx),") // hardware version + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(xxxx)") // counter + .text("$").optional() + .compile(); + private Object decodeVer(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_VER, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -554,9 +252,35 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } private void skipLocation(Parser parser) { - parser.skip(19); + parser.skip(20); } + private static final Pattern PATTERN_LOCATION = new PatternBuilder() + .number("(d{1,2}.?d?)?,") // hdop + .number("(d{1,3}.d)?,") // speed + .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 + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .groupBegin() + .number(",d+") // wifi count + .number("((?:,x{12},-d+,,,)+)") // wifi + .groupEnd("?") + .text(",") + .number("(d+)?,") // mcc + .number("(d+)?,") // mnc + .groupBegin() + .number("(d+),") // lac + .number("(d+),") // cid + .or() + .number("(x+)?,") // lac + .number("(x+)?,") // cid + .groupEnd() + .number("(?:d+|(d+.d))?,") // rssi / odometer + .compile(); + private void decodeLocation(Position position, Parser parser) { Double hdop = parser.nextDouble(); position.setValid(hdop == null || hdop > 0); @@ -575,22 +299,125 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { getLastLocation(position, null); } + Network network = new Network(); + + if (parser.hasNext()) { + String[] values = parser.next().split(","); + for (int i = 0; i < values.length; i += 5) { + String mac = values[i + 1].replaceAll("(..)", "$1:"); + network.addWifiAccessPoint(WifiAccessPoint.from( + mac.substring(0, mac.length() - 1), Integer.parseInt(values[i + 2]))); + } + } + if (parser.hasNext(6)) { int mcc = parser.nextInt(); int mnc = parser.nextInt(); if (parser.hasNext(2)) { - position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextInt(), parser.nextInt()))); + network.addCellTower(CellTower.from(mcc, mnc, parser.nextInt(), parser.nextInt())); } if (parser.hasNext(2)) { - position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt()))); + network.addCellTower(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt())); } } + if (network.getWifiAccessPoints() != null || network.getCellTowers() != null) { + position.setNetwork(network); + } + if (parser.hasNext()) { position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); } } + private int decodeLocation(Position position, String model, String[] values, int index) throws ParseException { + double hdop = values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1]); + position.set(Position.KEY_HDOP, hdop); + + position.setSpeed(UnitsConverter.knotsFromKph( + values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1]))); + position.setCourse(values[index++].isEmpty() ? 0 : Integer.parseInt(values[index - 1])); + position.setAltitude(values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1])); + + if (!values[index].isEmpty()) { + position.setValid(true); + position.setLongitude(values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1])); + position.setLatitude(values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1])); + position.setTime(dateFormat.parse(values[index++])); + } else { + index += 3; + getLastLocation(position, null); + } + + Network network = new Network(); + + if (!values[index].isEmpty()) { + network.addCellTower(CellTower.from( + Integer.parseInt(values[index++]), + Integer.parseInt(values[index++]), + Integer.parseInt(values[index++], 16), + Long.parseLong(values[index++], 16))); + } else { + index += 4; + } + + if (network.getWifiAccessPoints() != null || network.getCellTowers() != null) { + position.setNetwork(network); + } + + if (model.startsWith("GL5")) { + index += 1; // csq rssi + index += 1; // csq ber + } + + if (!values[index++].isEmpty()) { + int appendMask = Integer.parseInt(values[index - 1]); + if (BitUtil.check(appendMask, 0)) { + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); + } + if (BitUtil.check(appendMask, 1)) { + index += 1; // trigger type + } + } + + return index; + } + + private static final Pattern PATTERN_OBD = new PatternBuilder() + .text("+RESP:GTOBD,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("(?:[0-9A-Z]{17})?,") // vin + .expression("[^,]{0,20},") // device name + .expression("[01],") // report type + .number("x{1,8},") // report mask + .expression("(?:[0-9A-Z]{17})?,") // vin + .number("[01],") // obd connect + .number("(?:d{1,5})?,") // obd voltage + .number("(?:x{8})?,") // support pids + .number("(d{1,5})?,") // engine rpm + .number("(d{1,3})?,") // speed + .number("(-?d{1,3})?,") // coolant temp + .number("(d+.?d*|Inf|NaN)?,") // fuel consumption + .number("(d{1,5})?,") // dtcs cleared distance + .number("(?:d{1,5})?,") + .expression("([01])?,") // obd connect + .number("(d{1,3})?,") // number of dtcs + .number("(x*),") // dtcs + .number("(d{1,3})?,") // throttle + .number("(?:d{1,3})?,") // engine load + .number("(d{1,3})?,") // fuel level + .expression("(?:[0-9A],)?") // obd protocol + .number("(d+),") // odometer + .expression(PATTERN_LOCATION.pattern()) + .number("(d{1,7}.d)?,") // odometer + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_OBD, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -625,104 +452,140 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } - private Object decodeCan(Channel channel, SocketAddress remoteAddress, String sentence) throws ParseException { - Position position = new Position(getProtocolName()); - + private Object decodeCan(Channel channel, SocketAddress remoteAddress, String[] v) throws ParseException { int index = 0; - String[] values = sentence.split(","); - index += 1; // header index += 1; // protocol version + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, v[index++]); + if (deviceSession == null) { + return null; + } - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); + Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - index += 1; // device name + String model = getDeviceModel(deviceSession, v[index++]); index += 1; // report type - index += 1; // canbus state - long reportMask = Long.parseLong(values[index++], 16); + index += 1; // can bus state + long reportMask = Long.parseLong(v[index++], 16); long reportMaskExt = 0; if (BitUtil.check(reportMask, 0)) { - position.set(Position.KEY_VIN, values[index++]); + position.set(Position.KEY_VIN, v[index++]); } - if (BitUtil.check(reportMask, 1)) { - position.set(Position.KEY_IGNITION, Integer.parseInt(values[index++]) > 0); + if (BitUtil.check(reportMask, 1) && !v[index++].isEmpty()) { + position.set(Position.KEY_IGNITION, Integer.parseInt(v[index - 1]) > 0); } - if (BitUtil.check(reportMask, 2)) { - position.set(Position.KEY_OBD_ODOMETER, values[index++]); + if (BitUtil.check(reportMask, 2) && !v[index++].isEmpty()) { + position.set(Position.KEY_OBD_ODOMETER, Integer.parseInt(v[index - 1].substring(1))); } - if (BitUtil.check(reportMask, 3) && !values[index++].isEmpty()) { - position.set(Position.KEY_FUEL_USED, Double.parseDouble(values[index - 1])); + if (BitUtil.check(reportMask, 3) && !v[index++].isEmpty()) { + position.set(Position.KEY_FUEL_USED, Double.parseDouble(v[index - 1])); } - if (BitUtil.check(reportMask, 5) && !values[index++].isEmpty()) { - position.set(Position.KEY_RPM, Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMask, 5) && !v[index++].isEmpty()) { + position.set(Position.KEY_RPM, Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMask, 4) && !values[index++].isEmpty()) { - position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(Integer.parseInt(values[index - 1]))); + if (BitUtil.check(reportMask, 4) && !v[index++].isEmpty()) { + position.set(Position.KEY_OBD_SPEED, Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMask, 6) && !values[index++].isEmpty()) { - position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMask, 6) && !v[index++].isEmpty()) { + position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMask, 7) && !values[index++].isEmpty()) { - position.set(Position.KEY_FUEL_CONSUMPTION, Double.parseDouble(values[index - 1].substring(1))); + if (BitUtil.check(reportMask, 7) && !v[index++].isEmpty()) { + String value = v[index - 1]; + if (value.startsWith("L/H")) { + position.set(Position.KEY_FUEL_CONSUMPTION, Double.parseDouble(value.substring(3))); + } } - if (BitUtil.check(reportMask, 8) && !values[index++].isEmpty()) { - position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(values[index - 1].substring(1))); + if (BitUtil.check(reportMask, 8) && !v[index++].isEmpty()) { + position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(v[index - 1].substring(1))); } - if (BitUtil.check(reportMask, 9) && !values[index++].isEmpty()) { - position.set("range", Long.parseLong(values[index - 1]) * 100); + if (BitUtil.check(reportMask, 9) && !v[index++].isEmpty()) { + position.set("range", Long.parseLong(v[index - 1]) * 100); } - if (BitUtil.check(reportMask, 10) && !values[index++].isEmpty()) { - position.set(Position.KEY_THROTTLE, Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMask, 10) && !v[index++].isEmpty()) { + position.set(Position.KEY_THROTTLE, Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMask, 11) && !values[index++].isEmpty()) { - position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(Double.parseDouble(values[index - 1]))); + if (BitUtil.check(reportMask, 11) && !v[index++].isEmpty()) { + position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(Double.parseDouble(v[index - 1]))); } - if (BitUtil.check(reportMask, 12)) { - position.set("drivingHours", Double.parseDouble(values[index++])); + if (BitUtil.check(reportMask, 12) && !v[index++].isEmpty()) { + position.set(Position.KEY_DRIVING_TIME, Double.parseDouble(v[index - 1])); } - if (BitUtil.check(reportMask, 13)) { - position.set("idleHours", Double.parseDouble(values[index++])); + if (BitUtil.check(reportMask, 13) && !v[index++].isEmpty()) { + position.set("idleHours", Double.parseDouble(v[index - 1])); } - if (BitUtil.check(reportMask, 14) && !values[index++].isEmpty()) { - position.set("idleFuelConsumption", Double.parseDouble(values[index - 1])); + if (BitUtil.check(reportMask, 14) && !v[index++].isEmpty()) { + position.set("idleFuelConsumption", Double.parseDouble(v[index - 1])); } - if (BitUtil.check(reportMask, 15) && !values[index++].isEmpty()) { - position.set(Position.KEY_AXLE_WEIGHT, Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMask, 15) && !v[index++].isEmpty()) { + position.set(Position.KEY_AXLE_WEIGHT, Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMask, 16) && !values[index++].isEmpty()) { - position.set("tachographInfo", Integer.parseInt(values[index - 1], 16)); + if (BitUtil.check(reportMask, 16) && !v[index++].isEmpty()) { + position.set("tachographInfo", Integer.parseInt(v[index - 1], 16)); } - if (BitUtil.check(reportMask, 17) && !values[index++].isEmpty()) { - position.set("indicators", Integer.parseInt(values[index - 1], 16)); + if (BitUtil.check(reportMask, 17) && !v[index++].isEmpty()) { + position.set("indicators", Integer.parseInt(v[index - 1], 16)); } - if (BitUtil.check(reportMask, 18) && !values[index++].isEmpty()) { - position.set("lights", Integer.parseInt(values[index - 1], 16)); + if (BitUtil.check(reportMask, 18) && !v[index++].isEmpty()) { + position.set("lights", Integer.parseInt(v[index - 1], 16)); } - if (BitUtil.check(reportMask, 19) && !values[index++].isEmpty()) { - position.set("doors", Integer.parseInt(values[index - 1], 16)); + if (BitUtil.check(reportMask, 19) && !v[index++].isEmpty()) { + position.set("doors", Integer.parseInt(v[index - 1], 16)); } - if (BitUtil.check(reportMask, 20) && !values[index++].isEmpty()) { - position.set("vehicleOverspeed", Double.parseDouble(values[index - 1])); + if (BitUtil.check(reportMask, 20) && !v[index++].isEmpty()) { + position.set("vehicleOverspeed", Double.parseDouble(v[index - 1])); } - if (BitUtil.check(reportMask, 21) && !values[index++].isEmpty()) { - position.set("engineOverspeed", Double.parseDouble(values[index - 1])); + if (BitUtil.check(reportMask, 21) && !v[index++].isEmpty()) { + position.set("engineOverspeed", Double.parseDouble(v[index - 1])); } - if (BitUtil.check(reportMask, 29)) { - reportMaskExt = Long.parseLong(values[index++], 16); + if ("GV350M".equals(model)) { + if (BitUtil.check(reportMask, 22)) { + index += 1; // impulse distance + } + if (BitUtil.check(reportMask, 23)) { + index += 1; // gross vehicle weight + } + if (BitUtil.check(reportMask, 24)) { + index += 1; // catalyst liquid level + } + } else if ("GV355CEU".equals(model)) { + if (BitUtil.check(reportMask, 22)) { + index += 1; // impulse distance + } + if (BitUtil.check(reportMask, 23)) { + index += 1; // engine cold starts + } + if (BitUtil.check(reportMask, 24)) { + index += 1; // engine all starts + } + if (BitUtil.check(reportMask, 25)) { + index += 1; // engine starts by ignition + } + if (BitUtil.check(reportMask, 26)) { + index += 1; // total engine cold running time + } + if (BitUtil.check(reportMask, 27)) { + index += 1; // handbrake applies during ride + } + if (BitUtil.check(reportMask, 28)) { + index += 1; // electric report mask + } + } + if (BitUtil.check(reportMask, 29) && !v[index++].isEmpty()) { + reportMaskExt = Long.parseLong(v[index - 1], 16); } - if (BitUtil.check(reportMaskExt, 0) && !values[index++].isEmpty()) { - position.set("adBlueLevel", Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMaskExt, 0) && !v[index++].isEmpty()) { + position.set("adBlueLevel", Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMaskExt, 1) && !values[index++].isEmpty()) { - position.set("axleWeight1", Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMaskExt, 1) && !v[index++].isEmpty()) { + position.set("axleWeight1", Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMaskExt, 2) && !values[index++].isEmpty()) { - position.set("axleWeight3", Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMaskExt, 2) && !v[index++].isEmpty()) { + position.set("axleWeight3", Integer.parseInt(v[index - 1])); } - if (BitUtil.check(reportMaskExt, 3) && !values[index++].isEmpty()) { - position.set("axleWeight4", Integer.parseInt(values[index - 1])); + if (BitUtil.check(reportMaskExt, 3) && !v[index++].isEmpty()) { + position.set("axleWeight4", Integer.parseInt(v[index - 1])); } if (BitUtil.check(reportMaskExt, 4)) { index += 1; // tachograph overspeed @@ -733,8 +596,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(reportMaskExt, 6)) { index += 1; // tachograph direction } - if (BitUtil.check(reportMaskExt, 7) && !values[index++].isEmpty()) { - position.set(Position.PREFIX_ADC + 1, Integer.parseInt(values[index - 1]) * 0.001); + if (BitUtil.check(reportMaskExt, 7) && !v[index++].isEmpty()) { + position.set(Position.PREFIX_ADC + 1, Integer.parseInt(v[index - 1]) * 0.001); } if (BitUtil.check(reportMaskExt, 8)) { index += 1; // pedal breaking factor @@ -757,20 +620,20 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(reportMaskExt, 14)) { index += 1; // total brake application } - if (BitUtil.check(reportMaskExt, 15) && !values[index++].isEmpty()) { - position.set("driver1Card", values[index - 1]); + if (BitUtil.check(reportMaskExt, 15) && !v[index++].isEmpty()) { + position.set("driver1Card", v[index - 1]); } - if (BitUtil.check(reportMaskExt, 16) && !values[index++].isEmpty()) { - position.set("driver2Card", values[index - 1]); + if (BitUtil.check(reportMaskExt, 16) && !v[index++].isEmpty()) { + position.set("driver2Card", v[index - 1]); } - if (BitUtil.check(reportMaskExt, 17) && !values[index++].isEmpty()) { - position.set("driver1Name", values[index - 1]); + if (BitUtil.check(reportMaskExt, 17) && !v[index++].isEmpty()) { + position.set("driver1Name", v[index - 1]); } - if (BitUtil.check(reportMaskExt, 18) && !values[index++].isEmpty()) { - position.set("driver2Name", values[index - 1]); + if (BitUtil.check(reportMaskExt, 18) && !v[index++].isEmpty()) { + position.set("driver2Name", v[index - 1]); } - if (BitUtil.check(reportMaskExt, 19) && !values[index++].isEmpty()) { - position.set("registration", values[index - 1]); + if (BitUtil.check(reportMaskExt, 19) && !v[index++].isEmpty()) { + position.set("registration", v[index - 1]); } if (BitUtil.check(reportMaskExt, 20)) { index += 1; // expansion information @@ -788,18 +651,18 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - if (BitUtil.check(reportMask, 30)) { - while (values[index].isEmpty()) { + if (!"GV355CEU".equals(model) && BitUtil.check(reportMask, 30)) { + while (v[index].isEmpty()) { index += 1; } - position.setValid(Integer.parseInt(values[index++]) > 0); - if (!values[index].isEmpty()) { - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); - position.setCourse(Integer.parseInt(values[index++])); - position.setAltitude(Double.parseDouble(values[index++])); - position.setLongitude(Double.parseDouble(values[index++])); - position.setLatitude(Double.parseDouble(values[index++])); - position.setTime(dateFormat.parse(values[index++])); + position.setValid(Integer.parseInt(v[index++]) > 0); + if (!v[index].isEmpty()) { + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(v[index++]))); + position.setCourse(Integer.parseInt(v[index++])); + position.setAltitude(Double.parseDouble(v[index++])); + position.setLongitude(Double.parseDouble(v[index++])); + position.setLatitude(Double.parseDouble(v[index++])); + position.setTime(dateFormat.parse(v[index++])); } else { index += 6; // no location getLastLocation(position, null); @@ -813,34 +676,79 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { index += 1; // reserved } + index = v.length - 2; if (ignoreFixTime) { - position.setTime(dateFormat.parse(values[index])); + position.setTime(dateFormat.parse(v[index])); } else { - position.setDeviceTime(dateFormat.parse(values[index])); + position.setDeviceTime(dateFormat.parse(v[index])); } return position; } - private void decodeStatus(Position position, Parser parser) { - if (parser.hasNext(3)) { - int ignition = parser.nextHexInt(); - if (BitUtil.check(ignition, 4)) { - position.set(Position.KEY_IGNITION, false); - } else if (BitUtil.check(ignition, 5)) { - position.set(Position.KEY_IGNITION, true); - } - int input = parser.nextHexInt(); - int output = parser.nextHexInt(); - position.set(Position.KEY_INPUT, input); - position.set(Position.PREFIX_IN + 1, BitUtil.check(input, 1)); - position.set(Position.PREFIX_IN + 2, BitUtil.check(input, 2)); - position.set(Position.KEY_OUTPUT, output); - position.set(Position.PREFIX_OUT + 1, BitUtil.check(output, 0)); - position.set(Position.PREFIX_OUT + 2, BitUtil.check(output, 1)); - } + private void decodeStatus(Position position, long value) { + long ignition = BitUtil.between(value, 2 * 8, 3 * 8); + if (BitUtil.check(ignition, 4)) { + position.set(Position.KEY_IGNITION, false); + } else if (BitUtil.check(ignition, 5)) { + position.set(Position.KEY_IGNITION, true); + } + long input = BitUtil.between(value, 8, 2 * 8); + long output = BitUtil.to(value, 8); + position.set(Position.KEY_INPUT, input); + position.set(Position.PREFIX_IN + 1, BitUtil.check(input, 1)); + position.set(Position.PREFIX_IN + 2, BitUtil.check(input, 2)); + position.set(Position.KEY_OUTPUT, output); + position.set(Position.PREFIX_OUT + 1, BitUtil.check(output, 0)); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(output, 1)); } + private static final Pattern PATTERN_FRI = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GT...,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("(?:([0-9A-Z]{17}),)?") // vin + .expression("[^,]*,") // device name + .number("(d+)?,") // power + .number("(d{1,2}),").optional() // report type + .number("d{1,2},").optional() // count + .number("d*,").optional() // reserved + .number("(d+),").optional() // battery + .expression("((?:") + .expression(PATTERN_LOCATION.pattern()) + .expression(")+)") + .groupBegin() + .number("d{1,2},") + .number("(d{1,5})?,") // battery + .number("(d{1,3}),") // battery level + .number("[01],") // mode + .number("(?:[01])?,") // motion + .number("(-?d{1,2}.d)?,") // temperature + .or() + .number("(d{1,7}.d)?,") // odometer + .number("(d{5}:dd:dd)?,") // hour meter + .number("(x+)?,") // adc 1 + .number("(x+)?,") // adc 2 + .number("(d{1,3})?,") // battery + .number("(x{6})?,") // device status + .number("(d+)?,") // rpm + .number("(?:d+.?d*|Inf|NaN)?,") // fuel consumption + .number("(d+)?,") // fuel level + .or() + .number("(-?d),") // rssi + .number("(d{1,3}),") // battery + .or() + .number("(d{1,7}.d)?,").optional() // odometer + .number("(d{1,3})?,") // battery + .groupEnd() + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeFri(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_FRI, sentence); if (!parser.matches()) { @@ -883,8 +791,10 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } if (parser.hasNext()) { - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); } + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.PREFIX_TEMP + 1, parser.nextDouble()); if (parser.hasNext()) { position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); @@ -894,7 +804,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_ADC + 2, parser.next()); position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - decodeStatus(position, parser); + if (parser.hasNext()) { + decodeStatus(position, parser.nextHexLong()); + } position.set(Position.KEY_RPM, parser.nextInt()); position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); @@ -921,109 +833,112 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return positions; } - private Object decodeEri(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_ERI, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + private Object decodeEri(Channel channel, SocketAddress remoteAddress, String[] v) throws ParseException { + int index = 0; + index += 1; // header + index += 1; // protocol version + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, v[index++]); if (deviceSession == null) { return null; } - long mask = parser.nextHexLong(); + String model = getDeviceModel(deviceSession, v[index++]); + long mask = Long.parseLong(v[index++], 16); + Double power = v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001; + index += 1; // report type + int count = Integer.parseInt(v[index++]); LinkedList<Position> positions = new LinkedList<>(); - - Integer power = parser.nextInt(); - - Parser itemParser = new Parser(PATTERN_LOCATION, parser.next()); - while (itemParser.find()) { + for (int i = 0; i < count; i++) { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - - decodeLocation(position, itemParser); - + index = decodeLocation(position, model, v, index); positions.add(position); } Position position = positions.getLast(); + position.set(Position.KEY_POWER, power); - skipLocation(parser); - - if (power != null) { - position.set(Position.KEY_POWER, power * 0.001); + if (!model.startsWith("GL5")) { + position.set(Position.KEY_ODOMETER, v[index++].isEmpty() ? null : Double.parseDouble(v[index - 1]) * 1000); + position.set(Position.KEY_HOURS, parseHours(v[index++])); + position.set(Position.PREFIX_ADC + 1, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001); + } + if (model.startsWith("GV") && !model.startsWith("GV6")) { + position.set(Position.PREFIX_ADC + 2, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001); } - if (parser.hasNext(12)) { - - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); - position.set(Position.KEY_HOURS, parseHours(parser.next())); - position.set(Position.PREFIX_ADC + 1, parser.next()); - position.set(Position.PREFIX_ADC + 2, parser.next()); - position.set(Position.PREFIX_ADC + 3, parser.next()); - if (parser.hasNext(2)) { - position.set(Position.KEY_INPUT, parser.nextHexInt()); - position.set(Position.KEY_OUTPUT, parser.nextHexInt()); - } - if (parser.hasNext(4)) { - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - decodeStatus(position, parser); + position.set(Position.KEY_BATTERY_LEVEL, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1])); + if (model.startsWith("GL5")) { + index += 1; // mode selection + position.set(Position.KEY_MOTION, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) > 0); + } else { + if (!v[index++].isEmpty()) { + decodeStatus(position, Long.parseLong(v[index - 1])); } + index += 1; // reserved / uart device type + } - int index = 0; - String[] data = parser.next().split(","); - - index += 1; // device type - - if (BitUtil.check(mask, 0)) { - index += 1; // digital fuel sensor data - } + if (BitUtil.check(mask, 0)) { + position.set(Position.KEY_FUEL_LEVEL, Integer.parseInt(v[index++], 16)); + } - if (BitUtil.check(mask, 1)) { - int deviceCount = Integer.parseInt(data[index++]); - for (int i = 1; i <= deviceCount; i++) { - index += 1; // id - index += 1; // type - if (!data[index++].isEmpty()) { - position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(data[index - 1], 16) * 0.0625); - } + if (BitUtil.check(mask, 1)) { + int deviceCount = Integer.parseInt(v[index++]); + for (int i = 1; i <= deviceCount; i++) { + index += 1; // id + index += 1; // type + if (!v[index++].isEmpty()) { + position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(v[index - 1], 16) * 0.0625); } } + } - if (BitUtil.check(mask, 2)) { - index += 1; // can data - } + if (BitUtil.check(mask, 2)) { + index += 1; // can data + } - if (BitUtil.check(mask, 3) || BitUtil.check(mask, 4)) { - int deviceCount = Integer.parseInt(data[index++]); - for (int i = 1; i <= deviceCount; i++) { - index += 1; // type - if (BitUtil.check(mask, 3)) { - position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(data[index++])); - } - if (BitUtil.check(mask, 4)) { - index += 1; // volume - } + if (BitUtil.check(mask, 3) || BitUtil.check(mask, 4)) { + int deviceCount = Integer.parseInt(v[index++]); + for (int i = 1; i <= deviceCount; i++) { + index += 1; // type + if (BitUtil.check(mask, 3)) { + position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(v[index++])); + } + if (BitUtil.check(mask, 4)) { + index += 1; // volume } } - } - if (parser.hasNext()) { - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - } - - decodeDeviceTime(position, parser); + Date time = dateFormat.parse(v[v.length - 2]); if (ignoreFixTime) { + position.setTime(time); positions.clear(); positions.add(position); + } else { + position.setDeviceTime(time); } return positions; } + private static final Pattern PATTERN_IGN = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GTIG[NF],") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("d+,") // ignition off duration + .expression(PATTERN_LOCATION.pattern()) + .number("(d{5}:dd:dd)?,") // hour meter + .number("(d{1,7}.d)?,") // odometer + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeIgn(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_IGN, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1042,6 +957,21 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_LSW = new PatternBuilder() + .text("+RESP:").expression("GT[LT]SW,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("[01],") // type + .number("([01]),") // state + .expression(PATTERN_LOCATION.pattern()) + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeLsw(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_LSW, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1058,6 +988,24 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_IDA = new PatternBuilder() + .text("+RESP:GTIDA,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,,") // device name + .number("([^,]+),") // rfid + .expression("[01],") // report type + .number("1,") // count + .expression(PATTERN_LOCATION.pattern()) + .number("(d+.d),") // odometer + .text(",,,,") + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeIda(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_IDA, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1076,6 +1024,21 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_WIF = new PatternBuilder() + .text("+RESP:GTWIF,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("(d+),") // count + .number("((?:x{12},-?d+,,,,)+),,,,") // wifi + .number("(d{1,3}),") // battery + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeWif(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_WIF, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1102,6 +1065,19 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_GSM = new PatternBuilder() + .text("+RESP:GTGSM,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("(?:STR|CTN|NMR|RTL),") // fix type + .expression("(.*)") // cells + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeGsm(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_GSM, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1128,6 +1104,18 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_PNA = new PatternBuilder() + .text("+RESP:GT").expression("P[NF]A,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodePna(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_PNA, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1142,6 +1130,22 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_DAR = new PatternBuilder() + .text("+RESP:GTDAR,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("(d),") // warning type + .number("(d{1,2}),,,") // fatigue degree + .expression(PATTERN_LOCATION.pattern()) + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeDar(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_DAR, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1165,6 +1169,204 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_DTT = new PatternBuilder() + .text("+RESP:GTDTT,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,,,") // device name + .number("d,") // data type + .number("d+,") // data length + .number("(x+),") // data + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private Object decodeDtt(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_DTT, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + getLastLocation(position, null); + + String data = Unpooled.wrappedBuffer(DataConverter.parseHex(parser.next())) + .toString(StandardCharsets.US_ASCII); + if (data.contains("COMB")) { + position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(data.split(",")[2])); + } else { + position.set(Position.KEY_RESULT, data); + } + + decodeDeviceTime(position, parser); + + return position; + } + + private static final Pattern PATTERN_BAA = new PatternBuilder() + .text("+RESP:GTBAA,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("x+,") // index + .number("d,") // accessory type + .number("d,") // accessory model + .number("x+,") // alarm type + .number("(x{4}),") // append mask + .expression("((?:[^,]+,){0,6})") // accessory optionals + .expression(PATTERN_LOCATION.pattern()) + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private Object decodeBaa(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_BAA, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + int mask = parser.nextHexInt(); + String[] values = parser.next().split(","); + int index = 0; + if (BitUtil.check(mask, 0)) { + position.set("accessoryName", values[index++]); + } + if (BitUtil.check(mask, 1)) { + position.set("accessoryMac", values[index++]); + } + if (BitUtil.check(mask, 2)) { + position.set("accessoryStatus", Integer.parseInt(values[index++])); + } + if (BitUtil.check(mask, 3)) { + position.set("accessoryVoltage", Integer.parseInt(values[index++]) * 0.001); + } + if (BitUtil.check(mask, 4)) { + position.set("accessoryTemp", Integer.parseInt(values[index++])); + } + if (BitUtil.check(mask, 5)) { + position.set("accessoryHumidity", Integer.parseInt(values[index])); + } + + decodeLocation(position, parser); + + decodeDeviceTime(position, parser); + + return position; + } + + private static final Pattern PATTERN_BID = new PatternBuilder() + .text("+RESP:GTBID,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("d,") // count + .number("d,") // accessory model + .number("(x{4}),") // append mask + .expression("((?:[^,]+,){0,2})") // accessory optionals + .expression(PATTERN_LOCATION.pattern()) + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private Object decodeBid(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_BID, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + int mask = parser.nextHexInt(); + String[] values = parser.next().split(","); + int index = 0; + if (BitUtil.check(mask, 1)) { + position.set("accessoryMac", values[index++]); + } + if (BitUtil.check(mask, 3)) { + position.set("accessoryVoltage", Integer.parseInt(values[index]) * 0.001); + } + + decodeLocation(position, parser); + + decodeDeviceTime(position, parser); + + return position; + } + + private static final Pattern PATTERN_LSA = new PatternBuilder() + .text("+RESP:GTLSA,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("d,") // event state 1 + .number("d,") // event state 2 + .number("d+,") // number + .expression(PATTERN_LOCATION.pattern()) + .number("d+,") // bit error rate + .number("(d),") // light level + .number("(d+),") // battery level + .number("[01],") // mode selection + .number("[01]?,") // movement status + .number("(-?d+.d)?,") // temperature + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private Object decodeLsa(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_LSA, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + decodeLocation(position, parser); + + position.set("lightLevel", parser.nextInt()); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.PREFIX_TEMP + 1, parser.nextDouble()); + + decodeDeviceTime(position, parser); + + return position; + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GT...,") + .expression("(?:.{6}|.{10})?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("d*,") + .number("(x{1,2}),") // report type + .number("d{1,2},") // count + .number("d*,").optional() // reserved + .expression(PATTERN_LOCATION.pattern()) + .groupBegin() + .number("(?:(d{1,7}.d)|0)?,").optional() // odometer + .number("(d{1,3})?,") // battery + .or() + .number("(d{1,7}.d)?,") // odometer + .groupEnd() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)") // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeOther(Channel channel, SocketAddress remoteAddress, String sentence, String type) { Parser parser = new Parser(PATTERN, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1215,6 +1417,38 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_BASIC = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF)").text(":") + .expression("GT...,") + .expression("[^,]+,").optional() // protocol version + .number("(d{15}|x{14}),") // imei + .any() + .text(",") + .number("(d{1,2}),") // hdop + .groupBegin() + .number("(d{1,3}.d),") // speed + .number("(d{1,3}),") // course + .number("(-?d{1,5}.d),") // altitude + .number("(-?d{1,3}.d{6}),") // longitude + .number("(-?d{1,2}.d{6}),") // latitude + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)") // time (hhmmss) + .text(",") + .or() + .text(",,,,,,") + .groupEnd() + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(x+),") // lac + .number("(x+),").optional(4) // cell + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + private Object decodeBasic(Channel channel, SocketAddress remoteAddress, String sentence, String type) { Parser parser = new Parser(PATTERN_BASIC, sentence); Position position = initPosition(parser, channel, remoteAddress); @@ -1299,17 +1533,19 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - String sentence = ((ByteBuf) msg).toString(StandardCharsets.US_ASCII); + String sentence = ((ByteBuf) msg).toString(StandardCharsets.US_ASCII).replaceAll("\\$$", ""); int typeIndex = sentence.indexOf(":GT"); if (typeIndex < 0) { return null; } + String[] values = sentence.split(","); + Object result; String type = sentence.substring(typeIndex + 3, typeIndex + 6); if (sentence.startsWith("+ACK")) { - result = decodeAck(channel, remoteAddress, sentence, type); + result = decodeAck(channel, remoteAddress, values); } else { switch (type) { case "INF": @@ -1319,7 +1555,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { result = decodeObd(channel, remoteAddress, sentence); break; case "CAN": - result = decodeCan(channel, remoteAddress, sentence); + result = decodeCan(channel, remoteAddress, values); break; case "CTN": case "FRI": @@ -1330,7 +1566,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { result = decodeFri(channel, remoteAddress, sentence); break; case "ERI": - result = decodeEri(channel, remoteAddress, sentence); + result = decodeEri(channel, remoteAddress, values); break; case "IGN": case "IGF": @@ -1359,6 +1595,18 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { case "DAR": result = decodeDar(channel, remoteAddress, sentence); break; + case "DTT": + result = decodeDtt(channel, remoteAddress, sentence); + break; + case "BAA": + result = decodeBaa(channel, remoteAddress, sentence); + break; + case "BID": + result = decodeBid(channel, remoteAddress, sentence); + break; + case "LSA": + result = decodeLsa(channel, remoteAddress, sentence); + break; default: result = decodeOther(channel, remoteAddress, sentence, type); break; @@ -1380,13 +1628,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } if (channel != null && getConfig().getBoolean(Keys.PROTOCOL_ACK.withPrefix(getProtocolName()))) { - String checksum; - if (sentence.endsWith("$")) { - checksum = sentence.substring(sentence.length() - 1 - 4, sentence.length() - 1); - } else { - checksum = sentence.substring(sentence.length() - 4); - } - channel.writeAndFlush(new NetworkMessage("+SACK:" + checksum + "$", remoteAddress)); + channel.writeAndFlush(new NetworkMessage("+SACK:" + values[values.length - 1] + "$", remoteAddress)); } return result; diff --git a/src/main/java/org/traccar/protocol/GlobalSatProtocol.java b/src/main/java/org/traccar/protocol/GlobalSatProtocol.java index 16b99f426..13f4f2646 100644 --- a/src/main/java/org/traccar/protocol/GlobalSatProtocol.java +++ b/src/main/java/org/traccar/protocol/GlobalSatProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GlobalSatProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocol.java b/src/main/java/org/traccar/protocol/GlobalstarProtocol.java index 293f5fda5..1d9b6b6dd 100644 --- a/src/main/java/org/traccar/protocol/GlobalstarProtocol.java +++ b/src/main/java/org/traccar/protocol/GlobalstarProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GlobalstarProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java index 0ddb95c14..b75e612b8 100644 --- a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2023 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. @@ -27,6 +27,7 @@ import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.config.Keys; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -64,6 +65,12 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { private final XPath xPath; private final XPathExpression messageExpression; + private boolean alternative; + + public void setAlternative(boolean alternative) { + this.alternative = alternative; + } + public GlobalstarProtocolDecoder(Protocol protocol) { super(protocol); try { @@ -82,6 +89,11 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { } } + @Override + protected void init() { + this.alternative = getConfig().getBoolean(Keys.PROTOCOL_ALTERNATIVE.withPrefix(getProtocolName())); + } + private void sendResponse(Channel channel, String messageId) throws TransformerException { Document document = documentBuilder.newDocument(); @@ -135,32 +147,50 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - position.setValid(true); position.setTime(new Date(Long.parseLong(xPath.evaluate("unixTime", node)) * 1000)); ByteBuf buf = Unpooled.wrappedBuffer( DataConverter.parseHex(xPath.evaluate("payload", node).substring(2))); int flags = buf.readUnsignedByte(); - position.set(Position.PREFIX_IN + 1, !BitUtil.check(flags, 1)); - position.set(Position.PREFIX_IN + 2, !BitUtil.check(flags, 2)); - position.set(Position.KEY_CHARGE, !BitUtil.check(flags, 3)); - if (BitUtil.check(flags, 4)) { - position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); + int type; + if (alternative) { + type = BitUtil.to(flags, 1); + position.setValid(true); + position.set(Position.PREFIX_IN + 1, !BitUtil.check(flags, 1)); + position.set(Position.PREFIX_IN + 2, !BitUtil.check(flags, 2)); + position.set(Position.KEY_CHARGE, !BitUtil.check(flags, 3)); + if (BitUtil.check(flags, 4)) { + position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); + } + position.setCourse(BitUtil.from(flags, 5) * 45); + } else { + type = BitUtil.to(flags, 2); + if (BitUtil.check(flags, 2)) { + position.set("batteryReplace", true); + } + position.setValid(!BitUtil.check(flags, 3)); } - position.setCourse(BitUtil.from(flags, 5) * 45); - double latitude = buf.readUnsignedMedium() * 90.0 / (1 << 23); position.setLatitude(latitude > 90 ? latitude - 180 : latitude); double longitude = buf.readUnsignedMedium() * 180.0 / (1 << 23); position.setLongitude(longitude > 180 ? longitude - 360 : longitude); - int speed = buf.readUnsignedByte(); - position.setSpeed(UnitsConverter.knotsFromKph(speed)); - - position.set("batteryReplace", BitUtil.check(buf.readUnsignedByte(), 7)); + int speed = 0; + if (alternative) { + speed = buf.readUnsignedByte(); + position.setSpeed(UnitsConverter.knotsFromKph(speed)); + position.set("batteryReplace", BitUtil.check(buf.readUnsignedByte(), 7)); + } else if (type == 0) { + position.set(Position.KEY_INPUT, BitUtil.to(buf.readUnsignedByte(), 4)); + int other = buf.readUnsignedByte(); + if (BitUtil.check(other, 4)) { + position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); + } + position.set(Position.KEY_MOTION, BitUtil.check(other, 6)); + } if (speed != 0xff) { positions.add(position); diff --git a/src/main/java/org/traccar/protocol/GnxProtocol.java b/src/main/java/org/traccar/protocol/GnxProtocol.java index 32d642688..cfa496009 100644 --- a/src/main/java/org/traccar/protocol/GnxProtocol.java +++ b/src/main/java/org/traccar/protocol/GnxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GnxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GoSafeProtocol.java b/src/main/java/org/traccar/protocol/GoSafeProtocol.java index 607931500..c9c0456a0 100644 --- a/src/main/java/org/traccar/protocol/GoSafeProtocol.java +++ b/src/main/java/org/traccar/protocol/GoSafeProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GoSafeProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java b/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java index 77649a041..f17ea0e08 100644 --- a/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java @@ -93,14 +93,14 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder { position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(values[index - 1]))); } position.setCourse(Integer.parseInt(values[index++])); - if (index < values.length) { - position.setAltitude(Integer.parseInt(values[index++])); + if (index < values.length && !values[index++].isEmpty()) { + position.setAltitude(Integer.parseInt(values[index - 1])); } - if (index < values.length) { - position.set(Position.KEY_HDOP, Double.parseDouble(values[index++])); + if (index < values.length && !values[index++].isEmpty()) { + position.set(Position.KEY_HDOP, Double.parseDouble(values[index - 1])); } - if (index < values.length) { - position.set(Position.KEY_VDOP, Double.parseDouble(values[index++])); + if (index < values.length && !values[index++].isEmpty()) { + position.set(Position.KEY_VDOP, Double.parseDouble(values[index - 1])); } break; case "GSM": diff --git a/src/main/java/org/traccar/protocol/GotopProtocol.java b/src/main/java/org/traccar/protocol/GotopProtocol.java index 53fcea0d0..21fbbae99 100644 --- a/src/main/java/org/traccar/protocol/GotopProtocol.java +++ b/src/main/java/org/traccar/protocol/GotopProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GotopProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gps056Protocol.java b/src/main/java/org/traccar/protocol/Gps056Protocol.java index dbffbfdbb..44fc392be 100644 --- a/src/main/java/org/traccar/protocol/Gps056Protocol.java +++ b/src/main/java/org/traccar/protocol/Gps056Protocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gps056Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gps103Protocol.java b/src/main/java/org/traccar/protocol/Gps103Protocol.java index 2725494c5..8424abfe5 100644 --- a/src/main/java/org/traccar/protocol/Gps103Protocol.java +++ b/src/main/java/org/traccar/protocol/Gps103Protocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gps103Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java index 28efa3c30..d1c35b478 100644 --- a/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java @@ -225,7 +225,7 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder { getConfig(), parser.nextHexInt(0), parser.nextHexInt(0)))); } - if (parser.hasNext(20)) { + if (parser.hasNextAny(20)) { String utcHours = parser.next(); String utcMinutes = parser.next(); diff --git a/src/main/java/org/traccar/protocol/GpsGateProtocol.java b/src/main/java/org/traccar/protocol/GpsGateProtocol.java index a6a73ae6b..db1e8554a 100644 --- a/src/main/java/org/traccar/protocol/GpsGateProtocol.java +++ b/src/main/java/org/traccar/protocol/GpsGateProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GpsGateProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java b/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java index 12b53342c..f50088b2b 100644 --- a/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java +++ b/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GpsMarkerProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GpsmtaProtocol.java b/src/main/java/org/traccar/protocol/GpsmtaProtocol.java index a474b1e53..e146a816d 100644 --- a/src/main/java/org/traccar/protocol/GpsmtaProtocol.java +++ b/src/main/java/org/traccar/protocol/GpsmtaProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GpsmtaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/GranitProtocol.java b/src/main/java/org/traccar/protocol/GranitProtocol.java index bb66501e2..9ca0fe25e 100644 --- a/src/main/java/org/traccar/protocol/GranitProtocol.java +++ b/src/main/java/org/traccar/protocol/GranitProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class GranitProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gs100Protocol.java b/src/main/java/org/traccar/protocol/Gs100Protocol.java index 425ca9330..715d48fc4 100644 --- a/src/main/java/org/traccar/protocol/Gs100Protocol.java +++ b/src/main/java/org/traccar/protocol/Gs100Protocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gs100Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gt02Protocol.java b/src/main/java/org/traccar/protocol/Gt02Protocol.java index fa05761f6..f448feacc 100644 --- a/src/main/java/org/traccar/protocol/Gt02Protocol.java +++ b/src/main/java/org/traccar/protocol/Gt02Protocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gt02Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gt06Protocol.java b/src/main/java/org/traccar/protocol/Gt06Protocol.java index 38278121c..945ec3831 100644 --- a/src/main/java/org/traccar/protocol/Gt06Protocol.java +++ b/src/main/java/org/traccar/protocol/Gt06Protocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gt06Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 5b639ddfc..6c0380278 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2024 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.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.BufferUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -77,11 +78,12 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_HEARTBEAT = 0x23; // GK310 public static final int MSG_ADDRESS_REQUEST = 0x2A; // GK310 public static final int MSG_ADDRESS_RESPONSE = 0x97; // GK310 - public static final int MSG_GPS_LBS_5 = 0x31; // AZ735 - public static final int MSG_GPS_LBS_STATUS_4 = 0x32; // AZ735 - public static final int MSG_WIFI_5 = 0x33; // AZ735 - public static final int MSG_AZ735_GPS = 0x32; // AZ735 / only extended - public static final int MSG_AZ735_ALARM = 0x33; // AZ735 / only extended + public static final int MSG_GPS_LBS_5 = 0x31; // AZ735 & SL4X + public static final int MSG_GPS_LBS_STATUS_4 = 0x32; // AZ735 & SL4X + public static final int MSG_WIFI_5 = 0x33; // AZ735 & SL4X + public static final int MSG_LBS_3 = 0x34; // SL4X + public static final int MSG_AZ735_GPS = 0x32; // AZ735 (extended) + public static final int MSG_AZ735_ALARM = 0x33; // AZ735 (only extended) public static final int MSG_X1_GPS = 0x34; public static final int MSG_X1_PHOTO_INFO = 0x35; public static final int MSG_X1_PHOTO_DATA = 0x36; @@ -95,7 +97,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_INFO = 0x94; public static final int MSG_SERIAL = 0x9B; public static final int MSG_STRING_INFO = 0x21; - public static final int MSG_GPS_2 = 0xA0; // GK310 + public static final int MSG_GPS_LBS_7 = 0xA0; // GK310 & JM-VL03 public static final int MSG_LBS_2 = 0xA1; // GK310 public static final int MSG_WIFI_3 = 0xA2; // GK310 public static final int MSG_FENCE_SINGLE = 0xA3; // GK310 @@ -119,6 +121,10 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { SPACE10X, STANDARD, OBD6, + WETRUST, + JC400, + SL4X, + SEEWORLD, } private Variant variant; @@ -168,7 +174,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { case MSG_GPS_LBS_STATUS_4: case MSG_GPS_PHONE: case MSG_GPS_LBS_EXTEND: - case MSG_GPS_2: + case MSG_GPS_LBS_7: case MSG_FENCE_SINGLE: case MSG_FENCE_MULTI: return true; @@ -190,7 +196,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { case MSG_GPS_LBS_STATUS_2: case MSG_GPS_LBS_STATUS_3: case MSG_GPS_LBS_STATUS_4: - case MSG_GPS_2: + case MSG_GPS_LBS_7: case MSG_FENCE_SINGLE: case MSG_FENCE_MULTI: case MSG_LBS_ALARM: @@ -267,12 +273,12 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } public static boolean decodeGps(Position position, ByteBuf buf, boolean hasLength, TimeZone timezone) { - return decodeGps(position, buf, hasLength, true, true, timezone); + return decodeGps(position, buf, hasLength, true, true, false, timezone); } public static boolean decodeGps( Position position, ByteBuf buf, boolean hasLength, boolean hasSatellites, - boolean hasSpeed, TimeZone timezone) { + boolean hasSpeed, boolean longSpeed, TimeZone timezone) { DateBuilder dateBuilder = new DateBuilder(timezone) .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) @@ -291,7 +297,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { double longitude = buf.readUnsignedInt() / 60.0 / 30000.0; if (hasSpeed) { - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setSpeed(UnitsConverter.knotsFromKph( + longSpeed ? buf.readUnsignedShort() : buf.readUnsignedByte())); } int flags = buf.readUnsignedShort(); @@ -337,21 +344,21 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { int mcc = buf.readUnsignedShort(); int mnc; - if (BitUtil.check(mcc, 15) || type == MSG_GPS_LBS_6) { + if (BitUtil.check(mcc, 15) || type == MSG_GPS_LBS_6 || variant == Variant.SL4X) { mnc = buf.readUnsignedShort(); } else { mnc = buf.readUnsignedByte(); } int lac; - if (type == MSG_LBS_ALARM) { + if (type == MSG_LBS_ALARM || type == MSG_GPS_LBS_7) { lac = buf.readInt(); } else { lac = buf.readUnsignedShort(); } long cid; - if (type == MSG_LBS_ALARM) { + if (type == MSG_LBS_ALARM || type == MSG_GPS_LBS_7) { cid = buf.readLong(); - } else if (type == MSG_GPS_LBS_6) { + } else if (type == MSG_GPS_LBS_6 || variant == Variant.SEEWORLD) { cid = buf.readUnsignedInt(); } else { cid = buf.readUnsignedMedium(); @@ -434,15 +441,18 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { return Position.ALARM_REMOVING; case 0x23: return Position.ALARM_FALL_DOWN; + case 0x28: + return Position.ALARM_BRAKING; case 0x29: return Position.ALARM_ACCELERATION; - case 0x30: - return Position.ALARM_BRAKING; case 0x2A: case 0x2B: + case 0x2E: return Position.ALARM_CORNERING; case 0x2C: return Position.ALARM_ACCIDENT; + case 0x30: + return Position.ALARM_JAMMING; default: return null; } @@ -473,28 +483,21 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedShort(); // type deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession != null && !deviceSession.contains(DeviceSession.KEY_TIMEZONE)) { - deviceSession.set(DeviceSession.KEY_TIMEZONE, getTimeZone(deviceSession.getDeviceId())); - } - - if (dataLength > 10) { - int extensionBits = buf.readUnsignedShort(); - int hours = (extensionBits >> 4) / 100; - int minutes = (extensionBits >> 4) % 100; - int offset = (hours * 60 + minutes) * 60; - if ((extensionBits & 0x8) != 0) { - offset = -offset; - } - if (deviceSession != null) { - TimeZone timeZone = deviceSession.get(DeviceSession.KEY_TIMEZONE); - if (timeZone.getRawOffset() == 0) { - timeZone.setRawOffset(offset * 1000); - deviceSession.set(DeviceSession.KEY_TIMEZONE, timeZone); + if (deviceSession != null) { + TimeZone timeZone = getTimeZone(deviceSession.getDeviceId(), null); + if (timeZone == null && dataLength > 10) { + int extensionBits = buf.readUnsignedShort(); + int hours = (extensionBits >> 4) / 100; + int minutes = (extensionBits >> 4) % 100; + int offset = (hours * 60 + minutes) * 60; + if ((extensionBits & 0x8) != 0) { + offset = -offset; } + timeZone = TimeZone.getTimeZone("UTC"); + timeZone.setRawOffset(offset * 1000); } - } + deviceSession.set(DeviceSession.KEY_TIMEZONE, timeZone); - if (deviceSession != null) { sendResponse(channel, false, type, buf.getShort(buf.writerIndex() - 6), null); } @@ -545,7 +548,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { return null; - } else if (type == MSG_X1_GPS) { + } else if (type == MSG_X1_GPS && variant != Variant.SL4X) { buf.readUnsignedInt(); // data and alarm @@ -678,41 +681,50 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { return position; } else if (type == MSG_LBS_MULTIPLE_1 || type == MSG_LBS_MULTIPLE_2 || type == MSG_LBS_MULTIPLE_3 - || type == MSG_LBS_EXTEND || type == MSG_LBS_WIFI || type == MSG_LBS_2 + || type == MSG_LBS_EXTEND || type == MSG_LBS_WIFI || type == MSG_LBS_2 || type == MSG_LBS_3 || type == MSG_WIFI_3 || type == MSG_WIFI_5) { - boolean longFormat = type == MSG_LBS_2 || type == MSG_WIFI_3 || type == MSG_WIFI_5; - DateBuilder dateBuilder = new DateBuilder((TimeZone) deviceSession.get(DeviceSession.KEY_TIMEZONE)) .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); getLastLocation(position, dateBuilder.getDate()); - if (variant == Variant.WANWAY_S20) { + if (variant == Variant.WANWAY_S20 || variant == Variant.SL4X) { buf.readUnsignedByte(); // ta } int mcc = buf.readUnsignedShort(); - int mnc = BitUtil.check(mcc, 15) ? buf.readUnsignedShort() : buf.readUnsignedByte(); + int mnc = BitUtil.check(mcc, 15) || variant == Variant.SL4X + ? buf.readUnsignedShort() : buf.readUnsignedByte(); Network network = new Network(); int cellCount = variant == Variant.WANWAY_S20 ? buf.readUnsignedByte() : type == MSG_WIFI_5 ? 6 : 7; for (int i = 0; i < cellCount; i++) { - int lac = longFormat ? buf.readInt() : buf.readUnsignedShort(); - int cid = longFormat ? (int) buf.readLong() : buf.readUnsignedMedium(); + int lac; + int cid; + if (type == MSG_LBS_2 || type == MSG_WIFI_3) { + lac = buf.readInt(); + cid = (int) buf.readLong(); + } else if (type == MSG_WIFI_5 || type == MSG_LBS_3) { + lac = buf.readUnsignedShort(); + cid = (int) buf.readUnsignedInt(); + } else { + lac = buf.readUnsignedShort(); + cid = buf.readUnsignedMedium(); + } int rssi = -buf.readUnsignedByte(); if (lac > 0) { network.addCellTower(CellTower.from(BitUtil.to(mcc, 15), mnc, lac, cid, rssi)); } } - if (variant != Variant.WANWAY_S20) { + if (variant != Variant.WANWAY_S20 && variant != Variant.SL4X) { buf.readUnsignedByte(); // ta } if (type != MSG_LBS_MULTIPLE_1 && type != MSG_LBS_MULTIPLE_2 && type != MSG_LBS_MULTIPLE_3 - && type != MSG_LBS_2) { + && type != MSG_LBS_2 && type != MSG_LBS_3) { int wifiCount = buf.readUnsignedByte(); for (int i = 0; i < wifiCount; i++) { String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); @@ -805,7 +817,11 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } if (hasLbs(type) && buf.readableBytes() > 6) { - decodeLbs(position, buf, type, hasStatus(type) && type != MSG_LBS_ALARM && type != MSG_LBS_STATUS); + boolean hasLength = hasStatus(type) + && type != MSG_LBS_STATUS + && type != MSG_LBS_ALARM + && (type != MSG_GPS_LBS_STATUS_1 || variant != Variant.VXT01); + decodeLbs(position, buf, type, hasLength); } if (hasStatus(type)) { @@ -821,9 +837,13 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // working mode position.set(Position.KEY_POWER, buf.readUnsignedShort() / 100.0); } else { - position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 100 / 6); + int battery = buf.readUnsignedByte(); + position.set(Position.KEY_BATTERY_LEVEL, battery <= 6 ? battery * 100 / 6 : battery); position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + short alarmExtension = buf.readUnsignedByte(); + if (variant != Variant.VXT01) { + position.set(Position.KEY_ALARM, decodeAlarm(alarmExtension)); + } } } @@ -833,7 +853,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { String data = buf.readCharSequence(buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString(); buf.readUnsignedByte(); // alarm buf.readUnsignedByte(); // swiped - position.set("driverLicense", data.trim()); + position.set(Position.KEY_CARD, data.trim()); } else if (variant == Variant.BENWAY) { int mask = buf.readUnsignedShort(); position.set(Position.KEY_IGNITION, BitUtil.check(mask, 8 + 7)); @@ -869,9 +889,30 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } position.set(Position.PREFIX_TEMP + 1, temperature); position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 10); + } else if (variant == Variant.WETRUST) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + position.set(Position.KEY_CARD, buf.readCharSequence( + buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString()); + position.set(Position.KEY_ALARM, buf.readUnsignedByte() > 0 ? Position.ALARM_GENERAL : null); + position.set("cardStatus", buf.readUnsignedByte()); + position.set(Position.KEY_DRIVING_TIME, buf.readUnsignedShort()); } } + if (type == MSG_GPS_LBS_2 && variant == Variant.SEEWORLD) { + position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); + buf.readUnsignedByte(); // reporting mode + buf.readUnsignedByte(); // supplementary transmission + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + buf.readUnsignedInt(); // travel time + int temperature = buf.readUnsignedShort(); + if (BitUtil.check(temperature, 15)) { + temperature = -BitUtil.to(temperature, 15); + } + position.set(Position.PREFIX_TEMP + 1, temperature * 0.01); + position.set("humidity", buf.readUnsignedShort() * 0.01); + } + if ((type == MSG_GPS_LBS_2 || type == MSG_GPS_LBS_3 || type == MSG_GPS_LBS_4) && buf.readableBytes() >= 3 + 6) { position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); @@ -898,6 +939,12 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } } + if (buf.readableBytes() == 3 + 6 || buf.readableBytes() == 3 + 4 + 6) { + position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); + buf.readUnsignedByte(); // upload mode + position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() > 0 ? true : null); + } + if (buf.readableBytes() == 4 + 6) { position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); } @@ -906,24 +953,44 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { boolean extendedAlarm = dataLength > 7; if (extendedAlarm) { - decodeGps(position, buf, false, false, false, deviceSession.get(DeviceSession.KEY_TIMEZONE)); + if (variant == Variant.JC400) { + buf.readUnsignedShort(); // marker + buf.readUnsignedByte(); // version + } + decodeGps( + position, buf, false, + variant == Variant.JC400, variant == Variant.JC400, variant == Variant.JC400, + deviceSession.get(DeviceSession.KEY_TIMEZONE)); } else { DateBuilder dateBuilder = new DateBuilder((TimeZone) deviceSession.get(DeviceSession.KEY_TIMEZONE)) .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); getLastLocation(position, dateBuilder.getDate()); } - short alarmType = buf.readUnsignedByte(); - switch (alarmType) { + if (variant == Variant.JC400) { + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1); + } + short event = buf.readUnsignedByte(); + position.set(Position.KEY_EVENT, event); + switch (event) { case 0x01: position.set(Position.KEY_ALARM, extendedAlarm ? Position.ALARM_SOS : Position.ALARM_GENERAL); break; + case 0x0E: + position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); + break; + case 0x76: + position.set(Position.KEY_ALARM, Position.ALARM_TEMPERATURE); + break; case 0x80: position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); break; case 0x87: position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); break; + case 0x88: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; case 0x90: position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); break; @@ -937,7 +1004,6 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); break; default: - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); break; } @@ -1020,6 +1086,29 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort() * 0.01); return position; + } else if (subType == 0x04) { + + CharSequence content = buf.readCharSequence(buf.readableBytes() - 4 - 2, StandardCharsets.US_ASCII); + String[] values = content.toString().split(";"); + for (String value : values) { + String[] pair = value.split("="); + switch (pair[0]) { + case "ALM1": + case "ALM2": + case "ALM3": + position.set("alarm" + pair[0].charAt(3) + "Status", Integer.parseInt(pair[1], 16)); + case "STA1": + position.set("otherStatus", Integer.parseInt(pair[1], 16)); + break; + case "DYD": + position.set("engineStatus", Integer.parseInt(pair[1], 16)); + break; + default: + break; + } + } + return position; + } else if (subType == 0x05) { if (buf.readableBytes() >= 6 + 1 + 6) { @@ -1339,19 +1428,13 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { getLastLocation(position, null); buf.readUnsignedByte(); // external device type code - int length = buf.readableBytes() - 9; // line break + checksum + index + checksum + footer - if (length <= 0) { - return null; - } else if (length < 8) { - position.set( - Position.PREFIX_TEMP + 1, - Double.parseDouble(buf.readCharSequence(length - 1, StandardCharsets.US_ASCII).toString())); + ByteBuf data = buf.readSlice(buf.readableBytes() - 6); // index + checksum + footer + if (BufferUtil.isPrintable(data, data.readableBytes())) { + String value = data.readCharSequence(data.readableBytes(), StandardCharsets.US_ASCII).toString(); + position.set(Position.KEY_RESULT, value.trim()); } else { - buf.readUnsignedByte(); // card type - position.set( - Position.KEY_DRIVER_UNIQUE_ID, - buf.readCharSequence(length - 1, StandardCharsets.US_ASCII).toString()); + position.set(Position.KEY_RESULT, ByteBufUtil.hexDump(data)); } return position; @@ -1391,6 +1474,18 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { variant = Variant.SPACE10X; } else if (header == 0x7878 && type == MSG_STATUS && length == 0x13) { variant = Variant.OBD6; + } else if (header == 0x7878 && type == MSG_GPS_LBS_1 && length == 0x29) { + variant = Variant.WETRUST; + } else if (header == 0x7878 && type == MSG_ALARM && buf.getUnsignedShort(buf.readerIndex() + 4) == 0xffff) { + variant = Variant.JC400; + } else if (header == 0x7878 && type == MSG_LBS_3 && length == 0x37) { + variant = Variant.SL4X; + } else if (header == 0x7878 && type == MSG_GPS_LBS_STATUS_4 && length == 0x27) { + variant = Variant.SL4X; + } else if (header == 0x7878 && type == MSG_GPS_LBS_2 && length == 0x2f) { + variant = Variant.SEEWORLD; + } else if (header == 0x7878 && type == MSG_GPS_LBS_STATUS_1 && length == 0x26) { + variant = Variant.SEEWORLD; } else { variant = Variant.STANDARD; } diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java index dc5dd446f..fd6bb8451 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java @@ -23,7 +23,6 @@ import org.traccar.config.Keys; import org.traccar.helper.Checksum; import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Command; -import org.traccar.model.Device; import java.nio.charset.StandardCharsets; @@ -74,11 +73,11 @@ public class Gt06ProtocolEncoder extends BaseProtocolEncoder { String password = AttributeUtil.getDevicePassword( getCacheManager(), command.getDeviceId(), getProtocolName(), "123456"); - Device device = getCacheManager().getObject(Device.class, command.getDeviceId()); + String model = getDeviceModel(command.getDeviceId()); switch (command.getType()) { case Command.TYPE_ENGINE_STOP: - if ("G109".equals(device.getModel())) { + if ("G109".equals(model)) { return encodeContent(command.getDeviceId(), "DYD#"); } else if (alternative) { return encodeContent(command.getDeviceId(), "DYD," + password + "#"); @@ -86,7 +85,7 @@ public class Gt06ProtocolEncoder extends BaseProtocolEncoder { return encodeContent(command.getDeviceId(), "Relay,1#"); } case Command.TYPE_ENGINE_RESUME: - if ("G109".equals(device.getModel())) { + if ("G109".equals(model)) { return encodeContent(command.getDeviceId(), "HFYD#"); } else if (alternative) { return encodeContent(command.getDeviceId(), "HFYD," + password + "#"); diff --git a/src/main/java/org/traccar/protocol/Gt30Protocol.java b/src/main/java/org/traccar/protocol/Gt30Protocol.java index 6b79ba58b..fdfc80502 100644 --- a/src/main/java/org/traccar/protocol/Gt30Protocol.java +++ b/src/main/java/org/traccar/protocol/Gt30Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Gt30Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/H02Protocol.java b/src/main/java/org/traccar/protocol/H02Protocol.java index 4e5f8c96a..ba5aeaa26 100644 --- a/src/main/java/org/traccar/protocol/H02Protocol.java +++ b/src/main/java/org/traccar/protocol/H02Protocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class H02Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/HaicomProtocol.java b/src/main/java/org/traccar/protocol/HaicomProtocol.java index f56c605f0..bcc491ada 100644 --- a/src/main/java/org/traccar/protocol/HaicomProtocol.java +++ b/src/main/java/org/traccar/protocol/HaicomProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class HaicomProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/HomtecsProtocol.java b/src/main/java/org/traccar/protocol/HomtecsProtocol.java index aa2d7d852..c04efb945 100644 --- a/src/main/java/org/traccar/protocol/HomtecsProtocol.java +++ b/src/main/java/org/traccar/protocol/HomtecsProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class HomtecsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/HoopoProtocol.java b/src/main/java/org/traccar/protocol/HoopoProtocol.java index 02d8e5a8e..3fc0887d8 100644 --- a/src/main/java/org/traccar/protocol/HoopoProtocol.java +++ b/src/main/java/org/traccar/protocol/HoopoProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class HoopoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java index 708c74f2a..7433e7fce 100644 --- a/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java @@ -21,8 +21,8 @@ import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.time.OffsetDateTime; diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocol.java b/src/main/java/org/traccar/protocol/HuaShengProtocol.java index b1b61e977..7246e97e6 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocol.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2023 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,17 +19,25 @@ import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; +import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class HuaShengProtocol extends BaseProtocol { @Inject public HuaShengProtocol(Config config) { + setSupportedDataCommands( + Command.TYPE_POSITION_PERIODIC, + Command.TYPE_OUTPUT_CONTROL, + Command.TYPE_ALARM_ARM, + Command.TYPE_ALARM_DISARM, + Command.TYPE_SET_SPEED_LIMIT); addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { pipeline.addLast(new HuaShengFrameDecoder()); + pipeline.addLast(new HuaShengProtocolEncoder(HuaShengProtocol.this)); pipeline.addLast(new HuaShengProtocolDecoder(HuaShengProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java index 371691d82..7d634b0f2 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2023 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,6 +48,10 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_UPFAULT_RSP = 0xFF13; public static final int MSG_HSO_REQ = 0x0002; public static final int MSG_HSO_RSP = 0x0003; + public static final int MSG_SET_REQ = 0xAA04; + public static final int MSG_SET_RSP = 0xFF05; + public static final int MSG_CTRL_REQ = 0xAA16; + public static final int MSG_CTRL_RSP = 0xFF17; private void sendResponse(Channel channel, int type, int index, ByteBuf content) { if (channel != null) { @@ -225,13 +229,14 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { position.setCourse(buf.readUnsignedShort()); position.setAltitude(buf.readUnsignedShort()); - position.set(Position.KEY_ODOMETER, buf.readUnsignedShort() * 1000); + buf.readUnsignedShort(); // odometer speed Network network = new Network(); while (buf.readableBytes() > 4) { int subtype = buf.readUnsignedShort(); int length = buf.readUnsignedShort() - 4; + int endIndex = buf.readerIndex() + length; switch (subtype) { case 0x0001: int coolantTemperature = buf.readUnsignedByte() - 40; @@ -249,6 +254,9 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4); buf.readUnsignedInt(); // trip id + if (buf.readerIndex() < endIndex) { + position.set("adBlueLevel", buf.readUnsignedByte() * 0.4); + } break; case 0x0005: position.set(Position.KEY_RSSI, buf.readUnsignedByte()); @@ -256,8 +264,11 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedInt(); // run time break; case 0x0009: - position.set( - Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); + position.set(Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); + break; + case 0x0010: + position.set(Position.KEY_ODOMETER, Double.parseDouble( + buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()) * 1000); break; case 0x0011: position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 0.05); @@ -276,7 +287,7 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { String[] values = cell.split("@"); network.addCellTower(CellTower.from( Integer.parseInt(values[0]), Integer.parseInt(values[1]), - Integer.parseInt(values[2], 16), Integer.parseInt(values[3], 16))); + Integer.parseInt(values[2], 16), Long.parseLong(values[3], 16))); } break; case 0x0021: @@ -291,6 +302,7 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { buf.skipBytes(length); break; } + buf.readerIndex(endIndex); } if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) { diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java new file mode 100644 index 000000000..dc34f7b4e --- /dev/null +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java @@ -0,0 +1,85 @@ +/* + * Copyright 2023 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 org.traccar.BaseProtocolEncoder; +import org.traccar.Protocol; +import org.traccar.model.Command; + +public class HuaShengProtocolEncoder extends BaseProtocolEncoder { + + public HuaShengProtocolEncoder(Protocol protocol) { + super(protocol); + } + + private ByteBuf encodeContent(int type, ByteBuf content) { + + ByteBuf buf = Unpooled.buffer(); + buf.writeByte(0xC0); + buf.writeShort(0x0000); // flag and version + buf.writeShort(12 + content.readableBytes()); + buf.writeShort(type); + buf.writeShort(0); // checksum + buf.writeInt(1); // index + buf.writeBytes(content); + content.release(); + buf.writeByte(0xC0); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + ByteBuf content = Unpooled.buffer(0); + switch (command.getType()) { + case Command.TYPE_POSITION_PERIODIC: + content.writeShort(0x0002); + content.writeShort(6); // length + content.writeShort(command.getInteger(Command.KEY_FREQUENCY)); + return encodeContent(HuaShengProtocolDecoder.MSG_SET_REQ, content); + case Command.TYPE_OUTPUT_CONTROL: + /* +0x01: Lock the relay1; //relay on +0x02: Unlock the relay1; //relay off +0x03: Lock the relay2; //relay2 on +0x04: Unlock the relay2; //relay2 off +0x05: Lock the relay3; //relay3 on +0x06: Unlock the relay3; //realy3 off + */ + content.writeByte( + (command.getInteger(Command.KEY_INDEX) - 1) * 2 + + (2 - command.getInteger(Command.KEY_DATA))); + return encodeContent(HuaShengProtocolDecoder.MSG_CTRL_REQ, content); + case Command.TYPE_ALARM_ARM: + case Command.TYPE_ALARM_DISARM: + content.writeShort(0x0001); + content.writeShort(5); // length + content.writeByte(command.getType().equals(Command.TYPE_ALARM_ARM) ? 1 : 0); + return encodeContent(HuaShengProtocolDecoder.MSG_SET_REQ, content); + case Command.TYPE_SET_SPEED_LIMIT: + content.writeShort(0x0004); + content.writeShort(6); // length + content.writeShort(command.getInteger(Command.KEY_DATA)); + return encodeContent(HuaShengProtocolDecoder.MSG_SET_REQ, content); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocol.java b/src/main/java/org/traccar/protocol/HuabaoProtocol.java index c37918b0e..fc12d7d71 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocol.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class HuabaoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index d0bbeebb5..0a8540543 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2023 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. @@ -131,7 +131,10 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(value, 8)) { return Position.ALARM_POWER_OFF; } - if (BitUtil.check(value, 17)) { + if (BitUtil.check(value, 15)) { + return Position.ALARM_VIBRATION; + } + if (BitUtil.check(value, 16) || BitUtil.check(value, 17)) { return Position.ALARM_TAMPERING; } if (BitUtil.check(value, 20)) { @@ -140,7 +143,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(value, 28)) { return Position.ALARM_MOVEMENT; } - if (BitUtil.check(value, 29)) { + if (BitUtil.check(value, 29) || BitUtil.check(value, 30)) { return Position.ALARM_ACCIDENT; } return null; @@ -169,7 +172,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } else { long imei = id.getUnsignedShort(0); imei = (imei << 32) + id.getUnsignedInt(2); - return String.valueOf(imei); + return String.valueOf(imei) + Checksum.luhn(imei); } } @@ -294,6 +297,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } else if (type == MSG_TRANSPARENT) { + sendGeneralResponse(channel, remoteAddress, id, type, index); + return decodeTransparent(deviceSession, buf); } @@ -327,6 +332,16 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x03: position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() * 0.1); break; + case 0x56: + buf.readUnsignedByte(); // power level + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + break; + case 0x61: + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); + break; + case 0x69: + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); + break; case 0x80: position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte()); break; @@ -388,6 +403,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { int status = buf.readInt(); position.set(Position.KEY_IGNITION, BitUtil.check(status, 0)); + position.set(Position.KEY_MOTION, BitUtil.check(status, 4)); position.set(Position.KEY_BLOCKED, BitUtil.check(status, 10)); position.set(Position.KEY_CHARGE, BitUtil.check(status, 26)); @@ -448,6 +464,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { int subtype = buf.readUnsignedByte(); int length = buf.readUnsignedByte(); int endIndex = buf.readerIndex() + length; + String stringValue; switch (subtype) { case 0x01: position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100); @@ -455,8 +472,12 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x02: position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShort() * 0.1); break; + case 0x25: + position.set(Position.KEY_INPUT, buf.readUnsignedInt()); + break; case 0x2b: - position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt()); + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); break; case 0x30: position.set(Position.KEY_RSSI, buf.readUnsignedByte()); @@ -465,12 +486,75 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); break; case 0x33: - String sentence = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); - if (sentence.startsWith("*M00")) { - String lockStatus = sentence.substring(8, 8 + 7); + stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + if (stringValue.startsWith("*M00")) { + String lockStatus = stringValue.substring(8, 8 + 7); position.set(Position.KEY_BATTERY, Integer.parseInt(lockStatus.substring(2, 5)) * 0.01); } break; + case 0x56: + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 10); + buf.readUnsignedByte(); // reserved + break; + case 0x57: + int alarm = buf.readUnsignedShort(); + position.set(Position.KEY_ALARM, BitUtil.check(alarm, 8) ? Position.ALARM_ACCELERATION : null); + position.set(Position.KEY_ALARM, BitUtil.check(alarm, 9) ? Position.ALARM_BRAKING : null); + position.set(Position.KEY_ALARM, BitUtil.check(alarm, 10) ? Position.ALARM_CORNERING : null); + buf.readUnsignedShort(); // external switch state + buf.skipBytes(4); // reserved + break; + case 0x60: + int event = buf.readUnsignedShort(); + position.set(Position.KEY_EVENT, event); + if (event >= 0x0061 && event <= 0x0066) { + buf.skipBytes(6); // lock id + stringValue = buf.readCharSequence(8, StandardCharsets.US_ASCII).toString(); + position.set(Position.KEY_DRIVER_UNIQUE_ID, stringValue); + } + break; + case 0x63: + for (int i = 1; i <= length / 11; i++) { + position.set("lock" + i + "Id", ByteBufUtil.hexDump(buf.readSlice(6))); + position.set("lock" + i + "Battery", buf.readUnsignedShort() * 0.001); + position.set("lock" + i + "Seal", buf.readUnsignedByte() == 0x31); + buf.readUnsignedByte(); // physical state + buf.readUnsignedByte(); // rssi + } + break; + case 0x64: + buf.readUnsignedInt(); // alarm serial number + buf.readUnsignedByte(); // alarm status + position.set("adasAlarm", buf.readUnsignedByte()); + break; + case 0x65: + buf.readUnsignedInt(); // alarm serial number + buf.readUnsignedByte(); // alarm status + position.set("dmsAlarm", buf.readUnsignedByte()); + break; + case 0x70: + buf.readUnsignedInt(); // alarm serial number + buf.readUnsignedByte(); // alarm status + switch (buf.readUnsignedByte()) { + case 0x01: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 0x02: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 0x03: + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + break; + case 0x16: + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); + break; + default: + break; + } + break; + case 0x69: + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); + break; case 0x80: buf.readUnsignedByte(); // content endIndex = buf.writerIndex() - 2; @@ -492,8 +576,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { break; case 0x94: if (length > 0) { - position.set( - Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); + stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + position.set(Position.KEY_VIN, stringValue); } break; case 0xA7: @@ -503,6 +587,14 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0xAC: position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); break; + case 0xBC: + stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + position.set("driver", stringValue.trim()); + break; + case 0xBD: + stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + position.set(Position.KEY_DRIVER_UNIQUE_ID, stringValue); + break; case 0xD0: long userStatus = buf.readUnsignedInt(); if (BitUtil.check(userStatus, 3)) { @@ -513,7 +605,12 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1); break; case 0xD4: - position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + case 0xE1: + if (length == 1) { + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + } else { + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readUnsignedInt())); + } break; case 0xD5: if (length == 2) { @@ -536,6 +633,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_MOTION, BitUtil.check(deviceStatus, 2)); position.set("cover", BitUtil.check(deviceStatus, 3)); break; + case 0xE2: + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedInt() * 0.1); + break; case 0xE6: while (buf.readerIndex() < endIndex) { int sensorIndex = buf.readUnsignedByte(); @@ -589,8 +689,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } break; case 0xED: - String license = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim(); - position.set("driverLicense", license); + stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + position.set(Position.KEY_CARD, stringValue.trim()); break; case 0xEE: position.set(Position.KEY_RSSI, buf.readUnsignedByte()); @@ -663,6 +763,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0xFE: if (length == 1) { position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + } else if (length == 2) { + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1); } else { int mark = buf.readUnsignedByte(); if (mark == 0x7C) { @@ -721,12 +823,15 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { int battery = buf.readUnsignedByte(); if (battery <= 100) { position.set(Position.KEY_BATTERY_LEVEL, battery); - } else if (battery == 0xAA) { + } else if (battery == 0xAA || battery == 0xAB) { position.set(Position.KEY_CHARGE, true); } - position.setNetwork(new Network(CellTower.fromCidLac( - getConfig(), buf.readUnsignedInt(), buf.readUnsignedShort()))); + long cid = buf.readUnsignedInt(); + int lac = buf.readUnsignedShort(); + if (cid > 0 && lac > 0) { + position.setNetwork(new Network(CellTower.fromCidLac(getConfig(), cid, lac))); + } int product = buf.readUnsignedByte(); int status = buf.readUnsignedShort(); @@ -738,6 +843,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } } else if (product == 3) { position.set(Position.KEY_BLOCKED, BitUtil.check(status, 5)); + if (BitUtil.check(alarm, 0)) { + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + } if (BitUtil.check(alarm, 1)) { position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); } @@ -747,10 +855,69 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(alarm, 3)) { position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); } + if (BitUtil.check(alarm, 5)) { + position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_ENTER); + } + if (BitUtil.check(alarm, 6)) { + position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_EXIT); + } } position.set(Position.KEY_STATUS, status); + while (buf.readableBytes() > 2) { + int id = buf.readUnsignedByte(); + int length = buf.readUnsignedByte(); + switch (id) { + case 0x02: + position.setAltitude(buf.readShort()); + break; + case 0x10: + position.set("wakeSource", buf.readUnsignedByte()); + break; + case 0x0A: + if (length == 3) { + buf.readUnsignedShort(); // mcc + buf.readUnsignedByte(); // mnc + } else { + buf.skipBytes(length); + } + break; + case 0x0B: + position.set("lockCommand", buf.readUnsignedByte()); + if (length >= 5 && length <= 6) { + position.set("lockCard", buf.readUnsignedInt()); + } else if (length >= 7) { + position.set("lockPassword", buf.readCharSequence(6, StandardCharsets.US_ASCII).toString()); + } + if (length % 2 == 0) { + position.set("unlockResult", buf.readUnsignedByte()); + } + break; + case 0x0C: + int x = buf.readUnsignedShort(); + if (x > 0x8000) { + x -= 0x10000; + } + int y = buf.readUnsignedShort(); + if (y > 0x8000) { + y -= 0x10000; + } + int z = buf.readUnsignedShort(); + if (z > 0x8000) { + z -= 0x10000; + } + position.set("tilt", String.format("[%d,%d,%d]", x, y, z)); + break; + case 0xFC: + position.set(Position.KEY_GEOFENCE, buf.readUnsignedByte()); + break; + default: + buf.skipBytes(length); + break; + } + } + return position; } @@ -782,6 +949,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { int type = buf.readUnsignedByte(); if (type == 0xF0) { + Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); @@ -823,6 +991,34 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x0539: position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 0.01); break; + case 0x052B: + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte()); + break; + case 0x052D: + position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte() - 40); + break; + case 0x052E: + position.set("airTemp", buf.readUnsignedByte() - 40); + break; + case 0x0530: + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001); + break; + case 0x0535: + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() * 0.1); + break; + case 0x0536: + position.set(Position.KEY_RPM, buf.readUnsignedShort()); + break; + case 0x053D: + position.set("intakePressure", buf.readUnsignedShort() * 0.1); + break; + case 0x0544: + position.set("liquidLevel", buf.readUnsignedByte()); + break; + case 0x0547: + case 0x0548: + position.set(Position.KEY_THROTTLE, buf.readUnsignedByte()); + break; default: switch (length) { case 1: @@ -841,15 +1037,40 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { break; } } + getLastLocation(position, time); + decodeCoordinates(position, buf); + position.setTime(time); + break; + case 0x02: + List<String> codes = new LinkedList<>(); + count = buf.readUnsignedShort(); + for (int i = 0; i < count; i++) { + buf.readUnsignedInt(); // system id + int codeCount = buf.readUnsignedShort(); + for (int j = 0; j < codeCount; j++) { + buf.readUnsignedInt(); // dtc + buf.readUnsignedInt(); // status + codes.add(buf.readCharSequence( + buf.readUnsignedShort(), StandardCharsets.US_ASCII).toString().trim()); + } + } + position.set(Position.KEY_DTCS, String.join(" ", codes)); + getLastLocation(position, time); decodeCoordinates(position, buf); position.setTime(time); break; case 0x03: count = buf.readUnsignedByte(); for (int i = 0; i < count; i++) { - int id = buf.readUnsignedShort(); + int id = buf.readUnsignedByte(); int length = buf.readUnsignedByte(); switch (id) { + case 0x01: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED); + break; + case 0x02: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; case 0x1A: position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); break; @@ -867,11 +1088,21 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x23: position.set(Position.KEY_ALARM, Position.ALARM_FATIGUE_DRIVING); break; + case 0x26: + case 0x27: + case 0x28: + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); + break; + case 0x31: + case 0x32: + position.set(Position.KEY_ALARM, Position.ALARM_DOOR); + break; default: break; } buf.skipBytes(length); } + getLastLocation(position, time); decodeCoordinates(position, buf); position.setTime(time); break; @@ -886,6 +1117,24 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } return position; + + } else if (type == 0xFF) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + position.setTime(readDate(buf, deviceSession.get(DeviceSession.KEY_TIMEZONE))); + position.setLatitude(buf.readInt() * 0.000001); + position.setLongitude(buf.readInt() * 0.000001); + position.setAltitude(buf.readShort()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort() * 0.1)); + position.setCourse(buf.readUnsignedShort()); + + // TODO more positions and g sensor data + + return position; + } return null; diff --git a/src/main/java/org/traccar/protocol/HunterProProtocol.java b/src/main/java/org/traccar/protocol/HunterProProtocol.java index ed4289d73..64dab33b1 100644 --- a/src/main/java/org/traccar/protocol/HunterProProtocol.java +++ b/src/main/java/org/traccar/protocol/HunterProProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class HunterProProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/IdplProtocol.java b/src/main/java/org/traccar/protocol/IdplProtocol.java index aa1f4ff5b..1e44ad74c 100644 --- a/src/main/java/org/traccar/protocol/IdplProtocol.java +++ b/src/main/java/org/traccar/protocol/IdplProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class IdplProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/IntellitracProtocol.java b/src/main/java/org/traccar/protocol/IntellitracProtocol.java index b1a91cca9..a82e6a5db 100644 --- a/src/main/java/org/traccar/protocol/IntellitracProtocol.java +++ b/src/main/java/org/traccar/protocol/IntellitracProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class IntellitracProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/IotmProtocol.java b/src/main/java/org/traccar/protocol/IotmProtocol.java index 0d288f4bf..1631b67d8 100644 --- a/src/main/java/org/traccar/protocol/IotmProtocol.java +++ b/src/main/java/org/traccar/protocol/IotmProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class IotmProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java b/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java index 7bbe6c8de..d9e6670c6 100644 --- a/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2020 - 2023 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,27 +17,19 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; -import io.netty.channel.Channel; -import io.netty.handler.codec.mqtt.MqttConnectMessage; -import io.netty.handler.codec.mqtt.MqttConnectReturnCode; -import io.netty.handler.codec.mqtt.MqttMessage; -import io.netty.handler.codec.mqtt.MqttMessageBuilders; import io.netty.handler.codec.mqtt.MqttPublishMessage; -import io.netty.handler.codec.mqtt.MqttSubscribeMessage; -import org.traccar.BaseProtocolDecoder; -import org.traccar.session.DeviceSession; -import org.traccar.NetworkMessage; +import org.traccar.BaseMqttProtocolDecoder; import org.traccar.Protocol; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; +import org.traccar.session.DeviceSession; -import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.LinkedList; import java.util.List; -public class IotmProtocolDecoder extends BaseProtocolDecoder { +public class IotmProtocolDecoder extends BaseMqttProtocolDecoder { public IotmProtocolDecoder(Protocol protocol) { super(protocol); @@ -236,121 +228,72 @@ public class IotmProtocolDecoder extends BaseProtocolDecoder { @Override protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - if (msg instanceof MqttConnectMessage) { - - MqttConnectMessage message = (MqttConnectMessage) msg; + DeviceSession deviceSession, MqttPublishMessage message) throws Exception { - DeviceSession deviceSession = getDeviceSession( - channel, remoteAddress, message.payload().clientIdentifier()); - - MqttConnectReturnCode returnCode = deviceSession != null - ? MqttConnectReturnCode.CONNECTION_ACCEPTED - : MqttConnectReturnCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED; - - MqttMessage response = MqttMessageBuilders.connAck().returnCode(returnCode).build(); - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } + List<Position> positions = new LinkedList<>(); - } else if (msg instanceof MqttSubscribeMessage) { + ByteBuf buf = message.payload(); - MqttSubscribeMessage message = (MqttSubscribeMessage) msg; - - MqttMessage response = MqttMessageBuilders.subAck() - .packetId(message.variableHeader().messageId()) - .build(); - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - - } else if (msg instanceof MqttPublishMessage) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } + buf.readUnsignedByte(); // structure version - List<Position> positions = new LinkedList<>(); + while (buf.readableBytes() > 1) { + int type = buf.readUnsignedByte(); + int length = buf.readUnsignedShortLE(); + ByteBuf record = buf.readSlice(length); + if (type == 1) { - MqttPublishMessage message = (MqttPublishMessage) msg; - ByteBuf buf = message.payload(); + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.setTime(new Date(record.readUnsignedIntLE() * 1000)); - buf.readUnsignedByte(); // structure version + while (record.readableBytes() > 0) { + int sensorType = record.readUnsignedByte(); + int sensorId = record.readUnsignedShortLE(); + if (sensorType == 14) { - while (buf.readableBytes() > 1) { - int type = buf.readUnsignedByte(); - int length = buf.readUnsignedShortLE(); - ByteBuf record = buf.readSlice(length); - if (type == 1) { + position.setValid(true); + position.setLatitude(record.readFloatLE()); + position.setLongitude(record.readFloatLE()); + position.setSpeed(UnitsConverter.knotsFromKph(record.readUnsignedShortLE())); - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.setTime(new Date(record.readUnsignedIntLE() * 1000)); + position.set(Position.KEY_HDOP, record.readUnsignedByte()); + position.set(Position.KEY_SATELLITES, record.readUnsignedByte()); - while (record.readableBytes() > 0) { - int sensorType = record.readUnsignedByte(); - int sensorId = record.readUnsignedShortLE(); - if (sensorType == 14) { + position.setCourse(record.readUnsignedShortLE()); + position.setAltitude(record.readShortLE()); - position.setValid(true); - position.setLatitude(record.readFloatLE()); - position.setLongitude(record.readFloatLE()); - position.setSpeed(UnitsConverter.knotsFromKph(record.readUnsignedShortLE())); - - position.set(Position.KEY_HDOP, record.readUnsignedByte()); - position.set(Position.KEY_SATELLITES, record.readUnsignedByte()); - - position.setCourse(record.readUnsignedShortLE()); - position.setAltitude(record.readShortLE()); - - } else { - - if (sensorType == 3) { - continue; - } - - decodeSensor(position, record, sensorType, sensorId); + } else { + if (sensorType == 3) { + continue; } - } - - positions.add(position); - } else if (type == 3) { + decodeSensor(position, record, sensorType, sensorId); - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); + } + } - getLastLocation(position, new Date(record.readUnsignedIntLE() * 1000)); + positions.add(position); - record.readUnsignedByte(); // function identifier + } else if (type == 3) { - position.set(Position.KEY_EVENT, record.readUnsignedByte()); + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); - positions.add(position); + getLastLocation(position, new Date(record.readUnsignedIntLE() * 1000)); - } - } + record.readUnsignedByte(); // function identifier - buf.readUnsignedByte(); // checksum + position.set(Position.KEY_EVENT, record.readUnsignedByte()); - MqttMessage response = MqttMessageBuilders.pubAck() - .packetId(message.variableHeader().packetId()) - .build(); + positions.add(position); - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } - - return positions.isEmpty() ? null : positions; - } - return null; + buf.readUnsignedByte(); // checksum + + return positions.isEmpty() ? null : positions; } } diff --git a/src/main/java/org/traccar/protocol/ItsProtocol.java b/src/main/java/org/traccar/protocol/ItsProtocol.java index 5148e8ab0..7d59ea60c 100644 --- a/src/main/java/org/traccar/protocol/ItsProtocol.java +++ b/src/main/java/org/traccar/protocol/ItsProtocol.java @@ -23,7 +23,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ItsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Ivt401Protocol.java b/src/main/java/org/traccar/protocol/Ivt401Protocol.java index 763457641..5132c7467 100644 --- a/src/main/java/org/traccar/protocol/Ivt401Protocol.java +++ b/src/main/java/org/traccar/protocol/Ivt401Protocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Ivt401Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/JidoProtocol.java b/src/main/java/org/traccar/protocol/JidoProtocol.java index 78aa6c81c..b30cc586a 100644 --- a/src/main/java/org/traccar/protocol/JidoProtocol.java +++ b/src/main/java/org/traccar/protocol/JidoProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class JidoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/JpKorjarProtocol.java b/src/main/java/org/traccar/protocol/JpKorjarProtocol.java index 30c8e9977..ae312ea3e 100644 --- a/src/main/java/org/traccar/protocol/JpKorjarProtocol.java +++ b/src/main/java/org/traccar/protocol/JpKorjarProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class JpKorjarProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java b/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java index bfefb94a7..f7890f814 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 = Jt600ProtocolDecoder.isLongFormat(buf, buf.readerIndex() + 1); + boolean longFormat = Jt600ProtocolDecoder.isLongFormat(buf); 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 bf0b3379e..9dc62662f 100644 --- a/src/main/java/org/traccar/protocol/Jt600Protocol.java +++ b/src/main/java/org/traccar/protocol/Jt600Protocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Jt600Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java index 9ed44f565..eca7e2d11 100644 --- a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java @@ -86,8 +86,8 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { } - static boolean isLongFormat(ByteBuf buf, int flagIndex) { - return buf.getUnsignedByte(flagIndex) >> 4 >= 7; + static boolean isLongFormat(ByteBuf buf) { + return buf.getUnsignedByte(buf.readerIndex() + 8) == 0; } static void decodeBinaryLocation(ByteBuf buf, Position position) { @@ -105,15 +105,9 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { double longitude = convertCoordinate(BcdUtil.readInteger(buf, 9)); byte flags = buf.readByte(); - position.setValid((flags & 0x1) == 0x1); - if ((flags & 0x2) == 0) { - latitude = -latitude; - } - position.setLatitude(latitude); - if ((flags & 0x4) == 0) { - longitude = -longitude; - } - position.setLongitude(longitude); + position.setValid(BitUtil.check(flags, 0)); + position.setLatitude(BitUtil.check(flags, 1) ? latitude : -latitude); + position.setLongitude(BitUtil.check(flags, 2) ? longitude : -longitude); position.setSpeed(BcdUtil.readInteger(buf, 2)); position.setCourse(buf.readUnsignedByte() * 2.0); @@ -123,9 +117,9 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { List<Position> positions = new LinkedList<>(); - buf.readByte(); // header + boolean longFormat = isLongFormat(buf); - boolean longFormat = isLongFormat(buf, buf.readerIndex()); + buf.readByte(); // header String id = String.valueOf(Long.parseLong(ByteBufUtil.hexDump(buf.readSlice(5)))); DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); @@ -386,7 +380,7 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { .expression("([AV]),") // validity .number("(d+),") // speed .number("(d+),") // course - .number("d+,") // event source + .number("(d+),") // event source .number("d+,") // unlock verification .number("(d+),") // rfid .number("d+,") // password verification @@ -419,6 +413,8 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble())); position.setCourse(parser.nextDouble()); + position.set("eventSource", parser.nextInt()); + String rfid = parser.next(); if (!rfid.equals("0000000000")) { position.set(Position.KEY_DRIVER_UNIQUE_ID, rfid); diff --git a/src/main/java/org/traccar/protocol/KenjiProtocol.java b/src/main/java/org/traccar/protocol/KenjiProtocol.java index 8d78c8c56..b4e610cbd 100644 --- a/src/main/java/org/traccar/protocol/KenjiProtocol.java +++ b/src/main/java/org/traccar/protocol/KenjiProtocol.java @@ -24,7 +24,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class KenjiProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/KhdProtocol.java b/src/main/java/org/traccar/protocol/KhdProtocol.java index 521274de5..add13ef16 100644 --- a/src/main/java/org/traccar/protocol/KhdProtocol.java +++ b/src/main/java/org/traccar/protocol/KhdProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class KhdProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java index d7c236c4f..e88b34478 100644 --- a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java @@ -20,6 +20,7 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.BufferUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -169,7 +170,9 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_FUEL_LEVEL, BitUtil.from(odometer, 16)); } - position.set(Position.KEY_STATUS, buf.readUnsignedInt()); + long status = buf.readUnsignedInt(); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 7 + 3 * 8)); + position.set(Position.KEY_STATUS, status); buf.readUnsignedShort(); buf.readUnsignedByte(); @@ -185,8 +188,7 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedShort(); // data length int dataType = buf.readUnsignedByte(); - - buf.readUnsignedByte(); // content length + int dataLength = buf.readUnsignedByte(); switch (dataType) { case 0x01: @@ -197,6 +199,20 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedByte() * 100 + buf.readUnsignedByte()); break; + case 0x05: + int sign = buf.readUnsignedByte(); + switch (sign) { + case 1: + position.set("sign", true); + break; + case 2: + position.set("sign", false); + break; + default: + break; + } + position.set(Position.KEY_DRIVER_UNIQUE_ID, BufferUtil.readString(buf, dataLength - 1)); + break; case 0x18: for (int i = 1; i <= 4; i++) { double value = buf.readUnsignedShort(); @@ -205,6 +221,9 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder { } } break; + case 0x20: + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + break; case 0x23: Network network = new Network(); int count = buf.readUnsignedByte(); diff --git a/src/main/java/org/traccar/protocol/L100Protocol.java b/src/main/java/org/traccar/protocol/L100Protocol.java index 0edea6095..fa6d1b07e 100644 --- a/src/main/java/org/traccar/protocol/L100Protocol.java +++ b/src/main/java/org/traccar/protocol/L100Protocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class L100Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/LacakProtocol.java b/src/main/java/org/traccar/protocol/LacakProtocol.java index bbebd51ed..ddaf5078d 100644 --- a/src/main/java/org/traccar/protocol/LacakProtocol.java +++ b/src/main/java/org/traccar/protocol/LacakProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class LacakProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java b/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java index 809fafc90..66aab3490 100644 --- a/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java @@ -24,8 +24,8 @@ import org.traccar.Protocol; import org.traccar.helper.DateUtil; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/LaipacProtocol.java b/src/main/java/org/traccar/protocol/LaipacProtocol.java index 249d3bcbe..65b1a57e9 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocol.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class LaipacProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index e9570ee11..343d42e09 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -28,6 +28,7 @@ import org.traccar.helper.PatternBuilder; import org.traccar.model.CellTower; import org.traccar.model.Network; import org.traccar.model.Position; +import org.traccar.helper.BitUtil; import java.net.SocketAddress; import java.util.regex.Pattern; @@ -108,19 +109,31 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { } } - private String decodeEvent(String event, Position position) { + private String decodeEvent(String event, Position position, String model) { 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); + position.set(Position.PREFIX_IN + 1, (boolean) BitUtil.check(inputStatusInt, 0)); + position.set(Position.PREFIX_IN + 2, (boolean) BitUtil.check(inputStatusInt, 1)); + if ("SF-Lite".equals(model)) { + position.set(Position.PREFIX_IN + 3, false); + } + return null; + } else if (inputStatus >= 'O' && inputStatus <= 'R') { + int inputStatusInt = inputStatus - 'O'; + position.set(Position.PREFIX_IN + 1, (boolean) BitUtil.check(inputStatusInt, 0)); + position.set(Position.PREFIX_IN + 2, (boolean) BitUtil.check(inputStatusInt, 1)); + if ("SF-Lite".equals(model)) { + position.set(Position.PREFIX_IN + 3, true); + } return null; } } return event; + } private void sendEventResponse( @@ -132,6 +145,9 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { case "3": responseCode = "d"; break; + case "M": + responseCode = "m"; + break; case "S": case "T": responseCode = "t"; @@ -209,6 +225,8 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return null; } + String model = getDeviceModel(deviceSession); + Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); @@ -230,12 +248,17 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { String event = parser.next(); position.set(Position.KEY_ALARM, decodeAlarm(event)); - position.set(Position.KEY_EVENT, decodeEvent(event, position)); + position.set(Position.KEY_EVENT, decodeEvent(event, position, model)); position.set(Position.KEY_BATTERY, Double.parseDouble(parser.next().replaceAll("\\.", "")) * 0.001); 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); + + if ("AVL110".equals(model) || "AVL120".equals(model)) { + position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001); + } else { + parser.next(); + } Integer lac = parser.nextHexInt(); Integer cid = parser.nextHexInt(); diff --git a/src/main/java/org/traccar/protocol/LeafSpyProtocol.java b/src/main/java/org/traccar/protocol/LeafSpyProtocol.java index 7e13e23d0..9e167e7ba 100644 --- a/src/main/java/org/traccar/protocol/LeafSpyProtocol.java +++ b/src/main/java/org/traccar/protocol/LeafSpyProtocol.java @@ -24,7 +24,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class LeafSpyProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/M2cProtocol.java b/src/main/java/org/traccar/protocol/M2cProtocol.java index a23ea0f57..8abc30f60 100644 --- a/src/main/java/org/traccar/protocol/M2cProtocol.java +++ b/src/main/java/org/traccar/protocol/M2cProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class M2cProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/M2mProtocol.java b/src/main/java/org/traccar/protocol/M2mProtocol.java index 6809d800c..03a069d66 100644 --- a/src/main/java/org/traccar/protocol/M2mProtocol.java +++ b/src/main/java/org/traccar/protocol/M2mProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class M2mProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MaestroProtocol.java b/src/main/java/org/traccar/protocol/MaestroProtocol.java index 38a67f9a4..29f0b8897 100644 --- a/src/main/java/org/traccar/protocol/MaestroProtocol.java +++ b/src/main/java/org/traccar/protocol/MaestroProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MaestroProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ManPowerProtocol.java b/src/main/java/org/traccar/protocol/ManPowerProtocol.java index 492e86605..ba2414ca7 100644 --- a/src/main/java/org/traccar/protocol/ManPowerProtocol.java +++ b/src/main/java/org/traccar/protocol/ManPowerProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ManPowerProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Mavlink2Protocol.java b/src/main/java/org/traccar/protocol/Mavlink2Protocol.java index cf65a2db3..916fb7467 100644 --- a/src/main/java/org/traccar/protocol/Mavlink2Protocol.java +++ b/src/main/java/org/traccar/protocol/Mavlink2Protocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Mavlink2Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MegastekProtocol.java b/src/main/java/org/traccar/protocol/MegastekProtocol.java index 10215eb7c..9f8937f01 100644 --- a/src/main/java/org/traccar/protocol/MegastekProtocol.java +++ b/src/main/java/org/traccar/protocol/MegastekProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MegastekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocol.java b/src/main/java/org/traccar/protocol/MeiligaoProtocol.java index 492094ce3..d86a00fb3 100644 --- a/src/main/java/org/traccar/protocol/MeiligaoProtocol.java +++ b/src/main/java/org/traccar/protocol/MeiligaoProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MeiligaoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java index f3b56973a..1f8c4d2da 100644 --- a/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java @@ -282,7 +282,7 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_RSSI, parser.nextHexInt()); position.set(Position.KEY_ODOMETER, parser.nextHexLong()); position.set(Position.KEY_SATELLITES, parser.nextHexInt()); - position.set("driverLicense", parser.next()); + position.set(Position.KEY_CARD, parser.next()); position.set(Position.KEY_ODOMETER, parser.nextLong()); position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java b/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java index 5859d91ce..6d3b4f7e9 100644 --- a/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java @@ -24,7 +24,6 @@ import org.traccar.helper.Checksum; import org.traccar.helper.DataConverter; import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Command; -import org.traccar.model.Device; import java.nio.charset.StandardCharsets; import java.util.Set; @@ -64,7 +63,7 @@ public class MeiligaoProtocolEncoder extends BaseProtocolEncoder { int outputCount; int outputType; - String model = getCacheManager().getObject(Device.class, deviceId).getModel(); + String model = getDeviceModel(deviceId); if (model != null && Set.of("TK510", "GT08", "TK208", "TK228", "MT05").contains(model)) { outputCount = 5; diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocol.java b/src/main/java/org/traccar/protocol/MeitrackProtocol.java index c6eba8fe1..4109b22c9 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocol.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MeitrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java index 343141dca..88b6380a5 100644 --- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2023 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,10 +16,10 @@ 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.model.Device; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -30,12 +30,14 @@ 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.nio.charset.StandardCharsets; import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.Objects; import java.util.regex.Pattern; public class MeitrackProtocolDecoder extends BaseProtocolDecoder { @@ -204,11 +206,7 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_ADC + i, parser.nextHexInt()); } - String model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel(); - if (model == null) { - model = ""; - } - switch (model.toUpperCase()) { + switch (Objects.requireNonNullElse(getDeviceModel(deviceSession), "").toUpperCase()) { case "MVT340": case "MVT380": position.set(Position.KEY_BATTERY, parser.nextHexInt() * 3.0 * 2.0 / 1024.0); @@ -394,6 +392,8 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); + Network network = new Network(); + buf.readUnsignedShortLE(); // length buf.readUnsignedShortLE(); // index @@ -420,6 +420,12 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0x15: position.set(Position.KEY_INPUT, buf.readUnsignedByte()); break; + case 0x47: + int lockState = buf.readUnsignedByte(); + if (lockState > 0) { + position.set(Position.KEY_LOCK, lockState == 2); + } + break; case 0x97: position.set(Position.KEY_THROTTLE, buf.readUnsignedByte()); break; @@ -455,12 +461,18 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { case 0x16: position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE() * 0.01); break; + case 0x17: + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE() * 0.01); + break; case 0x19: position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); break; case 0x1A: position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.01); break; + case 0x29: + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShortLE() * 0.01); + break; case 0x40: position.set(Position.KEY_EVENT, buf.readUnsignedShortLE()); break; @@ -504,18 +516,26 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { position.setTime(new Date((946684800 + buf.readUnsignedIntLE()) * 1000)); // 2000-01-01 break; case 0x0C: - case 0x9B: position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); break; case 0x0D: position.set("runtime", buf.readUnsignedIntLE()); break; + case 0x25: + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readUnsignedIntLE())); + break; + case 0x9B: + position.set(Position.KEY_OBD_ODOMETER, buf.readUnsignedIntLE()); + break; case 0xA0: position.set(Position.KEY_FUEL_USED, buf.readUnsignedIntLE() * 0.001); break; case 0xA2: position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedIntLE() * 0.01); break; + case 0xFEF4: + position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 60000); + break; default: buf.readUnsignedIntLE(); break; @@ -528,6 +548,28 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { int id = extension ? buf.readUnsignedShort() : buf.readUnsignedByte(); int length = buf.readUnsignedByte(); switch (id) { + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + String wifiMac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); + network.addWifiAccessPoint(WifiAccessPoint.from( + wifiMac.substring(0, wifiMac.length() - 1), buf.readShortLE())); + break; + case 0x0E: + case 0x0F: + case 0x10: + case 0x12: + case 0x13: + network.addCellTower(CellTower.from( + buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), + buf.readUnsignedShortLE(), buf.readUnsignedIntLE(), buf.readShortLE())); + break; case 0x2A: case 0x2B: case 0x2C: @@ -539,17 +581,48 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // label position.set(Position.PREFIX_TEMP + (id - 0x2A), buf.readShortLE() * 0.01); break; + case 0x4B: + buf.skipBytes(length); // network information + break; case 0xFE31: buf.readUnsignedByte(); // alarm protocol buf.readUnsignedByte(); // alarm type buf.skipBytes(length - 2); break; + case 0xFE73: + buf.readUnsignedByte(); // version + position.set( + "tagName", + buf.readCharSequence(buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString()); + buf.skipBytes(6); // mac + position.set("tagBattery", buf.readUnsignedByte()); + position.set("tagTemp", buf.readUnsignedShortLE() / 256.0); + position.set("tagHumidity", buf.readUnsignedShortLE() / 256.0); + buf.readUnsignedShortLE(); // high temperature threshold + buf.readUnsignedShortLE(); // low temperature threshold + buf.readUnsignedShortLE(); // high humidity threshold + buf.readUnsignedShortLE(); // low humidity threshold + break; + case 0xFEA8: + for (int k = 1; k <= 3; k++) { + if (buf.readUnsignedByte() > 0) { + String key = k == 1 ? Position.KEY_BATTERY_LEVEL : "battery" + k + "Level"; + position.set(key, buf.readUnsignedByte()); + } else { + buf.readUnsignedByte(); + } + } + buf.readUnsignedByte(); // battery alert + break; default: buf.skipBytes(length); break; } } + if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) { + position.setNetwork(network); + } positions.add(position); } @@ -624,6 +697,13 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { photo = Unpooled.buffer(); requestPhotoPacket(channel, remoteAddress, imei, "camera_picture.jpg", 0); return null; + case "D82": + Position position = new Position(getProtocolName()); + position.setDeviceId(getDeviceSession(channel, remoteAddress, imei).getDeviceId()); + getLastLocation(position, null); + String result = buf.toString(index + 1, buf.writerIndex() - index - 4, StandardCharsets.US_ASCII); + position.set(Position.KEY_RESULT, result); + return position; case "CCC": return decodeBinaryC(channel, remoteAddress, buf); case "CCE": diff --git a/src/main/java/org/traccar/protocol/MictrackProtocol.java b/src/main/java/org/traccar/protocol/MictrackProtocol.java index ccbc4db4c..08bbe0c82 100644 --- a/src/main/java/org/traccar/protocol/MictrackProtocol.java +++ b/src/main/java/org/traccar/protocol/MictrackProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MictrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MilesmateProtocol.java b/src/main/java/org/traccar/protocol/MilesmateProtocol.java index 59212e791..607dfc5bf 100644 --- a/src/main/java/org/traccar/protocol/MilesmateProtocol.java +++ b/src/main/java/org/traccar/protocol/MilesmateProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MilesmateProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocol.java b/src/main/java/org/traccar/protocol/MiniFinderProtocol.java index 44599accc..1cb2a0007 100644 --- a/src/main/java/org/traccar/protocol/MiniFinderProtocol.java +++ b/src/main/java/org/traccar/protocol/MiniFinderProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MiniFinderProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java b/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java index f2e5eb905..1fdb1ece0 100644 --- a/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java @@ -143,7 +143,7 @@ public class MiniFinderProtocolDecoder extends BaseProtocolDecoder { } DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null || !sentence.matches("![35A-D],.*")) { + if (deviceSession == null || !sentence.matches("![345A-D],.*")) { return null; } @@ -161,6 +161,20 @@ public class MiniFinderProtocolDecoder extends BaseProtocolDecoder { return position; + } else if (type.equals("4")) { + + String[] values = sentence.split(","); + + getLastLocation(position, null); + + for (int i = 1; i <= 3; i++) { + if (!values[i + 1].isEmpty()) { + position.set("phone" + i, values[i + 1]); + } + } + + return position; + } else if (type.equals("5")) { String[] values = sentence.split(","); diff --git a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java index 5499a274e..082b9146d 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java +++ b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2023 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,19 +20,24 @@ import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; +import org.traccar.model.Command; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Minifinder2Protocol extends BaseProtocol { @Inject public Minifinder2Protocol(Config config) { + setSupportedDataCommands( + Command.TYPE_FIRMWARE_UPDATE, + Command.TYPE_CONFIGURATION); addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1200, 2, 2, 4, 0, true)); + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 2048, 2, 2, 4, 0, true)); + pipeline.addLast(new Minifinder2ProtocolEncoder(Minifinder2Protocol.this)); pipeline.addLast(new Minifinder2ProtocolDecoder(Minifinder2Protocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index 0b08badb8..64373e344 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2024 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.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.BufferUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -48,6 +49,8 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_DATA = 0x01; public static final int MSG_CONFIGURATION = 0x02; public static final int MSG_SERVICES = 0x03; + public static final int MSG_SYSTEM_CONTROL = 0x04; + public static final int MSG_FIRMWARE = 0x7E; public static final int MSG_RESPONSE = 0x7F; private String decodeAlarm(long code) { @@ -146,14 +149,13 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { int type = buf.readUnsignedByte(); if (BitUtil.check(flags, 4)) { - sendResponse(channel, remoteAddress, index, type, buf); + sendResponse(channel, remoteAddress, index, type, buf.slice()); } - if (type == MSG_DATA) { + if (type == MSG_DATA || type == MSG_SERVICES) { List<Position> positions = new LinkedList<>(); Set<Integer> keys = new HashSet<>(); - boolean hasLocation = false; Position position = new Position(getProtocolName()); DeviceSession deviceSession = null; @@ -163,12 +165,8 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { int key = buf.readUnsignedByte(); if (keys.contains(key)) { - if (!hasLocation) { - getLastLocation(position, null); - } positions.add(position); keys.clear(); - hasLocation = false; position = new Position(getProtocolName()); } keys.add(key); @@ -177,8 +175,9 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { case 0x01: deviceSession = getDeviceSession( channel, remoteAddress, buf.readCharSequence(15, StandardCharsets.US_ASCII).toString()); - - position.setDeviceId(deviceSession.getDeviceId()); + if (deviceSession == null) { + return null; + } break; case 0x02: long alarm = buf.readUnsignedIntLE(); @@ -192,7 +191,6 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); break; case 0x20: - hasLocation = true; position.setLatitude(buf.readIntLE() * 0.0000001); position.setLongitude(buf.readIntLE() * 0.0000001); position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); @@ -232,11 +230,18 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { position.setLatitude(buf.readIntLE() * 0.0000001); position.setLongitude(buf.readIntLE() * 0.0000001); position.setValid(true); - hasLocation = true; break; case 0x24: position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); long status = buf.readUnsignedIntLE(); + if (BitUtil.check(status, 4)) { + position.set(Position.KEY_CHARGE, true); + } + if (BitUtil.check(status, 7)) { + position.set(Position.KEY_ARCHIVE, true); + } + position.set(Position.KEY_MOTION, BitUtil.check(status, 9)); + position.set(Position.KEY_RSSI, BitUtil.between(status, 19, 24)); position.set(Position.KEY_BATTERY_LEVEL, BitUtil.from(status, 24)); position.set(Position.KEY_STATUS, status); break; @@ -249,7 +254,6 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { position.setLatitude(buf.readIntLE() * 0.0000001); position.setLongitude(buf.readIntLE() * 0.0000001); position.setValid(true); - hasLocation = true; } if (BitUtil.check(beaconFlags, 6)) { position.set("description", buf.readCharSequence( @@ -263,7 +267,6 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { position.setLatitude(buf.readIntLE() * 0.0000001); position.setLongitude(buf.readIntLE() * 0.0000001); position.setValid(true); - hasLocation = true; break; case 0x30: buf.readUnsignedIntLE(); // timestamp @@ -277,6 +280,14 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { i += 1; } break; + case 0x37: + buf.readUnsignedIntLE(); // timestamp + long barking = buf.readUnsignedIntLE(); + if (BitUtil.check(barking, 31)) { + position.set("barkStop", true); + } + position.set("barkCount", BitUtil.to(barking, 31)); + break; case 0x40: buf.readUnsignedIntLE(); // timestamp int heartRate = buf.readUnsignedByte(); @@ -290,14 +301,14 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { buf.readerIndex(endIndex); } - if (!hasLocation) { - getLastLocation(position, null); - } positions.add(position); if (deviceSession != null) { for (Position p : positions) { p.setDeviceId(deviceSession.getDeviceId()); + if (!p.getValid() && !p.hasAttribute(Position.KEY_HDOP)) { + getLastLocation(p, null); + } } } else { return null; @@ -305,9 +316,195 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { return positions; + } else if (type == MSG_CONFIGURATION) { + + return decodeConfiguration(channel, remoteAddress, buf); + + } else if (type == MSG_RESPONSE) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + buf.readUnsignedByte(); // length + position.set(Position.KEY_RESULT, String.valueOf(buf.readUnsignedByte())); + + return position; + } return null; } + private Position decodeConfiguration(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + while (buf.isReadable()) { + int length = buf.readUnsignedByte() - 1; + int endIndex = buf.readerIndex() + length + 1; + int key = buf.readUnsignedByte(); + + switch (key) { + case 0x01: + position.set("moduleNumber", buf.readUnsignedInt()); + break; + case 0x02: + position.set(Position.KEY_VERSION_FW, String.valueOf(buf.readUnsignedInt())); + break; + case 0x03: + position.set("imei", buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()); + break; + case 0x04: + position.set(Position.KEY_ICCID, BufferUtil.readString(buf, length)); + break; + case 0x05: + position.set("bleMac", ByteBufUtil.hexDump(buf.readSlice(length))); + break; + case 0x06: + position.set("settingTime", buf.readUnsignedInt()); + break; + case 0x07: + position.set("runTimes", buf.readUnsignedInt()); + break; + case 0x0A: + position.set("interval", buf.readUnsignedMedium()); + position.set("petMode", buf.readUnsignedByte()); + break; + case 0x0D: + position.set("passwordProtect", buf.readUnsignedInt()); + break; + case 0x0E: + position.set("timeZone", (int) buf.readByte()); + break; + case 0x0F: + position.set("enableControl", buf.readUnsignedInt()); + break; + case 0x13: + position.set("deviceName", BufferUtil.readString(buf, length)); + break; + case 0x14: + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); + break; + case 0x15: + position.set("bleLatitude", buf.readIntLE() * 0.0000001); + position.set("bleLongitude", buf.readIntLE() * 0.0000001); + position.set("bleLocation", BufferUtil.readString(buf, length - 8)); + break; + case 0x17: + position.set("gpsUrl", BufferUtil.readString(buf, length)); + break; + case 0x18: + position.set("lbsUrl", BufferUtil.readString(buf, length)); + break; + case 0x1A: + position.set("firmware", BufferUtil.readString(buf, length)); + break; + case 0x1B: + position.set("gsmModule", BufferUtil.readString(buf, length)); + break; + case 0x1D: + position.set("agpsUpdate", buf.readUnsignedByte()); + position.set("agpsLatitude", buf.readIntLE() * 0.0000001); + position.set("agpsLongitude", buf.readIntLE() * 0.0000001); + break; + case 0x30: + position.set("numberFlag", buf.readUnsignedByte()); + position.set("number", BufferUtil.readString(buf, length - 1)); + break; + case 0x31: + position.set("prefixFlag", buf.readUnsignedByte()); + position.set("prefix", BufferUtil.readString(buf, length - 1)); + break; + case 0x33: + position.set("phoneSwitches", buf.readUnsignedByte()); + break; + case 0x40: + position.set("apn", BufferUtil.readString(buf, length)); + break; + case 0x41: + position.set("apnUser", BufferUtil.readString(buf, length)); + break; + case 0x42: + position.set("apnPassword", BufferUtil.readString(buf, length)); + break; + case 0x43: + buf.readUnsignedByte(); // flag + position.set("port", buf.readUnsignedShort()); + position.set("server", BufferUtil.readString(buf, length - 3)); + break; + case 0x44: + position.set("heartbeatInterval", buf.readUnsignedInt()); + position.set("uploadInterval", buf.readUnsignedInt()); + position.set("uploadLazyInterval", buf.readUnsignedInt()); + break; + case 0x47: + position.set("deviceId", BufferUtil.readString(buf, length)); + break; + case 0x4E: + position.set("gsmBand", buf.readUnsignedByte()); + break; + case 0x50: + position.set("powerAlert", buf.readUnsignedInt()); + break; + case 0x51: + position.set("geoAlert", buf.readUnsignedInt()); + break; + case 0x53: + position.set("motionAlert", buf.readUnsignedInt()); + break; + case 0x5C: + position.set("barkLevel", buf.readUnsignedByte()); + position.set("barkInterval", buf.readUnsignedInt()); + break; + case 0x61: + position.set("msisdn", BufferUtil.readString(buf, length)); + break; + case 0x62: + position.set("wifiWhitelist", buf.readUnsignedByte()); + position.set("wifiWhitelistMac", ByteBufUtil.hexDump(buf.readSlice(6))); + break; + case 0x64: + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set("networkBand", buf.readUnsignedInt()); + position.set(Position.KEY_OPERATOR, BufferUtil.readString(buf, length - 5)); + break; + case 0x65: + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set("networkStatus", buf.readUnsignedByte()); + position.set("serverStatus", buf.readUnsignedByte()); + position.set("networkPlmn", ByteBufUtil.hexDump(buf.readSlice(6))); + position.set("homePlmn", ByteBufUtil.hexDump(buf.readSlice(6))); + break; + case 0x66: + position.set("imsi", BufferUtil.readString(buf, length)); + break; + case 0x75: + position.set("extraEnableControl", buf.readUnsignedInt()); + break; + default: + break; + } + + buf.readerIndex(endIndex); + } + + return position; + } + } diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java new file mode 100644 index 000000000..6e330a4dd --- /dev/null +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java @@ -0,0 +1,72 @@ +/* + * Copyright 2023 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 org.traccar.BaseProtocolEncoder; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; + +public class Minifinder2ProtocolEncoder extends BaseProtocolEncoder { + + public Minifinder2ProtocolEncoder(Protocol protocol) { + super(protocol); + } + + private ByteBuf encodeContent(ByteBuf content) { + + ByteBuf buf = Unpooled.buffer(); + + buf.writeByte(0xAB); // header + buf.writeByte(0x00); // properties + buf.writeShortLE(content.readableBytes()); + buf.writeShortLE(Checksum.crc16(Checksum.CRC16_XMODEM, content.nioBuffer())); + buf.writeShortLE(1); // index + buf.writeBytes(content); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + if (command.getType().equals(Command.TYPE_CONFIGURATION)) { + ByteBuf content = Unpooled.buffer(); + content.writeByte(Minifinder2ProtocolDecoder.MSG_CONFIGURATION); + content.writeByte(1); // length + content.writeByte(0xF0); // type + } + + if ("Nano".equalsIgnoreCase(getDeviceModel(command.getDeviceId()))) { + ByteBuf content = Unpooled.buffer(); + if (command.getType().equals(Command.TYPE_FIRMWARE_UPDATE)) { + String url = command.getString(Command.KEY_DATA); + content.writeByte(Minifinder2ProtocolDecoder.MSG_SYSTEM_CONTROL); + content.writeByte(1 + url.length()); + content.writeByte(0x30); // type + content.writeCharSequence(url, StandardCharsets.US_ASCII); + return encodeContent(content); + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/MobilogixProtocol.java b/src/main/java/org/traccar/protocol/MobilogixProtocol.java index 1b06c2249..36d6b5ed2 100644 --- a/src/main/java/org/traccar/protocol/MobilogixProtocol.java +++ b/src/main/java/org/traccar/protocol/MobilogixProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MobilogixProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MoovboxProtocol.java b/src/main/java/org/traccar/protocol/MoovboxProtocol.java index 16438e122..af853fe67 100644 --- a/src/main/java/org/traccar/protocol/MoovboxProtocol.java +++ b/src/main/java/org/traccar/protocol/MoovboxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MoovboxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MotorProtocol.java b/src/main/java/org/traccar/protocol/MotorProtocol.java index 3101c9b75..f17886577 100644 --- a/src/main/java/org/traccar/protocol/MotorProtocol.java +++ b/src/main/java/org/traccar/protocol/MotorProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MotorProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Mta6Protocol.java b/src/main/java/org/traccar/protocol/Mta6Protocol.java index 019fe4fa9..c1c6eb829 100644 --- a/src/main/java/org/traccar/protocol/Mta6Protocol.java +++ b/src/main/java/org/traccar/protocol/Mta6Protocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.config.Keys; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Mta6Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java index 896c7a2d2..9704cf099 100644 --- a/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java @@ -96,7 +96,7 @@ public class Mta6ProtocolDecoder extends BaseProtocolDecoder { } - private static class TimeReader extends FloatReader { + private static final class TimeReader extends FloatReader { private long weekNumber; diff --git a/src/main/java/org/traccar/protocol/MtxProtocol.java b/src/main/java/org/traccar/protocol/MtxProtocol.java index e085b6221..12d324019 100644 --- a/src/main/java/org/traccar/protocol/MtxProtocol.java +++ b/src/main/java/org/traccar/protocol/MtxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MtxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/MxtProtocol.java b/src/main/java/org/traccar/protocol/MxtProtocol.java index 1190bf527..2f0cc1658 100644 --- a/src/main/java/org/traccar/protocol/MxtProtocol.java +++ b/src/main/java/org/traccar/protocol/MxtProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class MxtProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NavigilProtocol.java b/src/main/java/org/traccar/protocol/NavigilProtocol.java index 46a6c33a5..a309235c5 100644 --- a/src/main/java/org/traccar/protocol/NavigilProtocol.java +++ b/src/main/java/org/traccar/protocol/NavigilProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NavigilProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NavisProtocol.java b/src/main/java/org/traccar/protocol/NavisProtocol.java index 640a77803..96b5b0de0 100644 --- a/src/main/java/org/traccar/protocol/NavisProtocol.java +++ b/src/main/java/org/traccar/protocol/NavisProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NavisProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NavisetProtocol.java b/src/main/java/org/traccar/protocol/NavisetProtocol.java index 388f141f8..6df0b0436 100644 --- a/src/main/java/org/traccar/protocol/NavisetProtocol.java +++ b/src/main/java/org/traccar/protocol/NavisetProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NavisetProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocol.java b/src/main/java/org/traccar/protocol/NavtelecomProtocol.java index 50013d1a4..de5f93df1 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocol.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NavtelecomProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 08b1a8d0f..cd7ffa0e1 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -193,12 +193,12 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - for (int j = 0; j < bits.length(); j++) { - if (bits.get(j)) { + for (int j = 1; j <= bits.length(); j++) { + if (bits.get(j - 1)) { int value; - switch (j + 1) { + switch (j) { case 1: position.set(Position.KEY_INDEX, buf.readUnsignedIntLE()); break; @@ -208,6 +208,18 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 3: position.setDeviceTime(new Date(buf.readUnsignedIntLE() * 1000)); break; + case 4: + value = buf.readUnsignedByte(); + position.set( + Position.KEY_ALARM, + BitUtil.check(value, 2) ? Position.ALARM_GENERAL : null); + int guardMode = BitUtil.between(value, 3, 4); + position.set(Position.KEY_ARMED, (0 < guardMode) && (guardMode < 3)); + break; + case 5: + value = buf.readUnsignedByte(); + position.set(Position.KEY_ROAMING, BitUtil.check(value, 6) ? true : null); + break; case 8: value = buf.readUnsignedByte(); position.setValid(BitUtil.check(value, 1)); @@ -232,7 +244,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { position.setCourse(buf.readUnsignedShortLE()); break; case 15: - position.set(Position.KEY_ODOMETER, buf.readFloatLE()); + position.set(Position.KEY_ODOMETER, buf.readFloatLE() * 1000); break; case 19: position.set(Position.KEY_POWER, buf.readShortLE() * 0.001); @@ -246,7 +258,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 24: case 25: case 26: - position.set(Position.PREFIX_ADC + (j + 2 - 21), buf.readUnsignedShortLE() * 0.001); + position.set(Position.PREFIX_ADC + (j + 1 - 21), buf.readUnsignedShortLE() * 0.001); break; case 29: value = buf.readUnsignedByte(); @@ -262,14 +274,14 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { break; case 33: case 34: - position.set(Position.PREFIX_COUNT + (j + 2 - 33), buf.readUnsignedIntLE()); + position.set(Position.PREFIX_COUNT + (j + 1 - 33), buf.readUnsignedIntLE()); break; case 35: case 36: - position.set("freq" + (j + 2 - 35), buf.readUnsignedShortLE()); + position.set("freq" + (j + 1 - 35), buf.readUnsignedShortLE()); break; case 37: - position.set(Position.KEY_HOURS, buf.readUnsignedIntLE()); + position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 1000); break; case 38: case 39: @@ -278,7 +290,8 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 42: case 43: value = buf.readUnsignedShortLE(); - position.set("fuel" + (j + 2 - 38), (value < 65500) ? value : null); + position.set( + Position.KEY_FUEL_LEVEL + (j + 1 - 38), (value < 65500) ? value : null); break; case 44: value = buf.readUnsignedShortLE(); @@ -294,8 +307,75 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 52: value = buf.readByte(); position.set( - Position.PREFIX_TEMP + (j + 2 - 45), - (value != (byte) 0x80) ? value : null); + Position.PREFIX_TEMP + (j + 1 - 45), (value != (byte) 0x80) ? value : null); + break; + case 53: + value = buf.readUnsignedShortLE(); + if (value != 0x7FFF) { + if (BitUtil.check(value, 15)) { + position.set("obdFuelLevel", BitUtil.to(value, 14)); + } else { + position.set("obdFuel", BitUtil.to(value, 14) * 0.1); + } + } + break; + case 54: + double fuelUsed = buf.readFloatLE() * 0.5; + position.set(Position.KEY_FUEL_USED, (fuelUsed >= 0) ? fuelUsed : null); + break; + case 55: + value = buf.readUnsignedShortLE(); + position.set(Position.KEY_RPM, (value != 0xFFFF) ? value : null); + break; + case 56: + value = buf.readByte(); + position.set(Position.KEY_COOLANT_TEMP, (value != (byte) 0x80) ? value : null); + break; + case 57: + position.set(Position.KEY_OBD_ODOMETER, buf.readFloatLE() * 1000); + break; + case 58: + case 59: + case 60: + case 61: + case 62: + value = buf.readUnsignedShortLE(); + position.set("axleWeight" + (j + 1 - 58), (value != 0xFFFF) ? value : null); + break; + case 63: + value = buf.readUnsignedByte(); + position.set("acceleratorPosition", (value != 0xFF) ? value : null); + break; + case 64: + value = buf.readUnsignedByte(); + position.set("brakePosition", (value != 0xFF) ? value : null); + break; + case 65: + value = buf.readUnsignedByte(); + position.set(Position.KEY_ENGINE_LOAD, (value != 0xFF) ? value : null); + break; + case 66: + value = buf.readUnsignedShortLE(); + if (value != 0x7FFF) { + if (BitUtil.check(value, 15)) { + position.set("obdAdBlueLevel", BitUtil.to(value, 14)); + } else { + position.set("obdAdBlue", BitUtil.to(value, 14) * 0.1); + } + } + break; + case 67: + position.set("obdHours", buf.readUnsignedIntLE() * 1000); + break; + case 68: + value = buf.readUnsignedShortLE(); + position.set( + Position.KEY_ODOMETER_SERVICE, + (value != 0xFFFF) ? (value * 5000) : null); + break; + case 69: + value = buf.readUnsignedByte(); + position.set(Position.KEY_OBD_SPEED, (value != 0xFF) ? value : null); break; case 78: case 79: @@ -303,10 +383,39 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 81: case 82: case 83: - position.set("fuelTemp" + (j + 2 - 78), (int) buf.readByte()); + position.set("fuelTemp" + (j + 1 - 78), (int) buf.readByte()); + break; + case 163: + case 164: + case 165: + case 166: + value = buf.readShortLE(); + position.set( + Position.PREFIX_TEMP + (j + 1 + 8 - 163), + (value != (short) 0x8000) ? value * 0.05 : null); + break; + case 167: + case 168: + case 169: + case 170: + value = buf.readUnsignedByte(); + position.set("humidity" + (j + 1 - 167), (value != 0xFF) ? value * 0.5 : null); + break; + case 206: + position.set("diagnostic", buf.readUnsignedIntLE()); break; default: - buf.skipBytes(getItemLength(j + 1)); + if ((207 <= j) && (j <= 222)) { + position.set("user1Byte" + (j + 1 - 207), buf.readUnsignedByte()); + } else if ((223 <= j) && (j <= 237)) { + position.set("user2Byte" + (j + 1 - 223), buf.readUnsignedShortLE()); + } else if ((238 <= j) && (j <= 252)) { + position.set("user4Byte" + (j + 1 - 238), buf.readUnsignedIntLE()); + } else if ((253 <= j) && (j <= 255)) { + position.set("user8Byte" + (j + 1 - 253), buf.readLongLE()); + } else { + buf.skipBytes(getItemLength(j)); + } break; } } diff --git a/src/main/java/org/traccar/protocol/NdtpV6Protocol.java b/src/main/java/org/traccar/protocol/NdtpV6Protocol.java index ce0dbbef2..9493132f5 100644 --- a/src/main/java/org/traccar/protocol/NdtpV6Protocol.java +++ b/src/main/java/org/traccar/protocol/NdtpV6Protocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NdtpV6Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NeosProtocol.java b/src/main/java/org/traccar/protocol/NeosProtocol.java index 0787b6562..16a6ba5a0 100644 --- a/src/main/java/org/traccar/protocol/NeosProtocol.java +++ b/src/main/java/org/traccar/protocol/NeosProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NeosProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NetProtocol.java b/src/main/java/org/traccar/protocol/NetProtocol.java index f27e4afb8..e011660da 100644 --- a/src/main/java/org/traccar/protocol/NetProtocol.java +++ b/src/main/java/org/traccar/protocol/NetProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NetProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NiotProtocol.java b/src/main/java/org/traccar/protocol/NiotProtocol.java index 0fbe0c689..7eacd5ff3 100644 --- a/src/main/java/org/traccar/protocol/NiotProtocol.java +++ b/src/main/java/org/traccar/protocol/NiotProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NiotProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NoranProtocol.java b/src/main/java/org/traccar/protocol/NoranProtocol.java index 626991029..d03e52be5 100644 --- a/src/main/java/org/traccar/protocol/NoranProtocol.java +++ b/src/main/java/org/traccar/protocol/NoranProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NoranProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NtoProtocol.java b/src/main/java/org/traccar/protocol/NtoProtocol.java new file mode 100644 index 000000000..d3596e287 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NtoProtocol.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023 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 jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class NtoProtocol extends BaseProtocol { + + @Inject + public NtoProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '&')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new NtoProtocolDecoder(NtoProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/NtoProtocolDecoder.java b/src/main/java/org/traccar/protocol/NtoProtocolDecoder.java new file mode 100644 index 000000000..ba9ebd95d --- /dev/null +++ b/src/main/java/org/traccar/protocol/NtoProtocolDecoder.java @@ -0,0 +1,92 @@ +/* + * Copyright 2023 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.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class NtoProtocolDecoder extends BaseProtocolDecoder { + + public NtoProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("^NB,") // manufacturer + .number("(d+),") // imei + .expression("(...),") // type + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AVM]),") // validity + .number("([NS]),(dd)(dd.d+),") // latitude + .number("([EW]),(ddd)(dd.d+),") // longitude + .number("(d+.?d*),") // speed + .number("(d+),") // course + .number("(x+),") // status + .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.set(Position.KEY_TYPE, parser.next()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextInt()); + + long status = parser.nextHexLong(); + position.set(Position.KEY_STATUS, status); + position.set(Position.KEY_ALARM, BitUtil.check(status, 1) ? Position.ALARM_JAMMING : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 3 * 8 + 1) ? Position.ALARM_POWER_CUT : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 3 * 8 + 2) ? Position.ALARM_OVERSPEED : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 3 * 8 + 3) ? Position.ALARM_VIBRATION : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 3 * 8 + 4) ? Position.ALARM_GEOFENCE_ENTER : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 3 * 8 + 5) ? Position.ALARM_GEOFENCE_EXIT : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 4 * 8) ? Position.ALARM_LOW_BATTERY : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 4 * 8 + 4) ? Position.ALARM_DOOR : null); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/NvsProtocol.java b/src/main/java/org/traccar/protocol/NvsProtocol.java index 7ed488e38..8a4ece30d 100644 --- a/src/main/java/org/traccar/protocol/NvsProtocol.java +++ b/src/main/java/org/traccar/protocol/NvsProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NvsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/NyitechProtocol.java b/src/main/java/org/traccar/protocol/NyitechProtocol.java index e7ef10945..225b1bd5a 100644 --- a/src/main/java/org/traccar/protocol/NyitechProtocol.java +++ b/src/main/java/org/traccar/protocol/NyitechProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class NyitechProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ObdDongleProtocol.java b/src/main/java/org/traccar/protocol/ObdDongleProtocol.java index 94f450426..9fcc35d0d 100644 --- a/src/main/java/org/traccar/protocol/ObdDongleProtocol.java +++ b/src/main/java/org/traccar/protocol/ObdDongleProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ObdDongleProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OigoProtocol.java b/src/main/java/org/traccar/protocol/OigoProtocol.java index 0539bada6..3483f8270 100644 --- a/src/main/java/org/traccar/protocol/OigoProtocol.java +++ b/src/main/java/org/traccar/protocol/OigoProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OigoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OkoProtocol.java b/src/main/java/org/traccar/protocol/OkoProtocol.java index 29c8bc1b9..6ca6c0e93 100644 --- a/src/main/java/org/traccar/protocol/OkoProtocol.java +++ b/src/main/java/org/traccar/protocol/OkoProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OkoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OmnicommProtocol.java b/src/main/java/org/traccar/protocol/OmnicommProtocol.java index dd400c779..b59b84132 100644 --- a/src/main/java/org/traccar/protocol/OmnicommProtocol.java +++ b/src/main/java/org/traccar/protocol/OmnicommProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OmnicommProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OpenGtsProtocol.java b/src/main/java/org/traccar/protocol/OpenGtsProtocol.java index 5443b4ffc..24d6de706 100644 --- a/src/main/java/org/traccar/protocol/OpenGtsProtocol.java +++ b/src/main/java/org/traccar/protocol/OpenGtsProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OpenGtsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OrbcommProtocol.java b/src/main/java/org/traccar/protocol/OrbcommProtocol.java index fb09f0abb..06b00619c 100644 --- a/src/main/java/org/traccar/protocol/OrbcommProtocol.java +++ b/src/main/java/org/traccar/protocol/OrbcommProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerClient; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OrbcommProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java b/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java index 1164d72a1..7ed13d647 100644 --- a/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java @@ -24,10 +24,10 @@ import org.traccar.Protocol; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.json.JsonValue; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/OrionProtocol.java b/src/main/java/org/traccar/protocol/OrionProtocol.java index 2dec7cd06..b78af462b 100644 --- a/src/main/java/org/traccar/protocol/OrionProtocol.java +++ b/src/main/java/org/traccar/protocol/OrionProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OrionProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OsmAndProtocol.java b/src/main/java/org/traccar/protocol/OsmAndProtocol.java index a86bc70d7..e06580949 100644 --- a/src/main/java/org/traccar/protocol/OsmAndProtocol.java +++ b/src/main/java/org/traccar/protocol/OsmAndProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OsmAndProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OutsafeProtocol.java b/src/main/java/org/traccar/protocol/OutsafeProtocol.java index 0099be456..159534883 100644 --- a/src/main/java/org/traccar/protocol/OutsafeProtocol.java +++ b/src/main/java/org/traccar/protocol/OutsafeProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OutsafeProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java b/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java index 62b873be7..f71778412 100644 --- a/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java @@ -23,11 +23,11 @@ import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonNumber; -import javax.json.JsonObject; -import javax.json.JsonString; -import javax.json.JsonValue; +import jakarta.json.Json; +import jakarta.json.JsonNumber; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/OwnTracksProtocol.java b/src/main/java/org/traccar/protocol/OwnTracksProtocol.java index 9ad337f19..c509ad282 100644 --- a/src/main/java/org/traccar/protocol/OwnTracksProtocol.java +++ b/src/main/java/org/traccar/protocol/OwnTracksProtocol.java @@ -24,7 +24,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class OwnTracksProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java b/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java index 71ac87168..e54d07fa7 100644 --- a/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java @@ -25,8 +25,8 @@ import org.traccar.Protocol; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/PacificTrackProtocol.java b/src/main/java/org/traccar/protocol/PacificTrackProtocol.java index 709729ef1..a315d4d9f 100644 --- a/src/main/java/org/traccar/protocol/PacificTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/PacificTrackProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PacificTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PathAwayProtocol.java b/src/main/java/org/traccar/protocol/PathAwayProtocol.java index 1d13eea95..a65740475 100644 --- a/src/main/java/org/traccar/protocol/PathAwayProtocol.java +++ b/src/main/java/org/traccar/protocol/PathAwayProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PathAwayProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocol.java b/src/main/java/org/traccar/protocol/PiligrimProtocol.java index aa45a0def..9dd1bc491 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocol.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PiligrimProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PluginProtocol.java b/src/main/java/org/traccar/protocol/PluginProtocol.java index b2101b18d..fff1830e8 100644 --- a/src/main/java/org/traccar/protocol/PluginProtocol.java +++ b/src/main/java/org/traccar/protocol/PluginProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PluginProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PolteProtocol.java b/src/main/java/org/traccar/protocol/PolteProtocol.java index 69666cc0e..0fbedfb09 100644 --- a/src/main/java/org/traccar/protocol/PolteProtocol.java +++ b/src/main/java/org/traccar/protocol/PolteProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PolteProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java b/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java index 028de5424..8954db491 100644 --- a/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java @@ -23,8 +23,8 @@ import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/PortmanProtocol.java b/src/main/java/org/traccar/protocol/PortmanProtocol.java index de78013fa..3a4b49289 100644 --- a/src/main/java/org/traccar/protocol/PortmanProtocol.java +++ b/src/main/java/org/traccar/protocol/PortmanProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PortmanProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java b/src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java index da9403313..716f2694b 100644 --- a/src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2020 - 2023 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,11 @@ public class PortmanProtocolDecoder extends BaseProtocolDecoder { } private static final Pattern PATTERN_STANDARD = new PatternBuilder() + .groupBegin() .text("$PTMLA,") // header + .or() + .text("%%") // header + .groupEnd() .expression("([^,]+),") // id .expression("([ABCL]),") // validity .number("(dd)(dd)(dd)") // date (yymmdd) @@ -47,12 +51,19 @@ public class PortmanProtocolDecoder extends BaseProtocolDecoder { .number("(d+),") // course .number("(?:NA|C(-?d+)),") // temperature .number("(x{8}),") // status - .number("(?:NA|(d+)),") // card id + .groupBegin() + .text("NA") + .or() + .number("F(d+)") // fuel + .or() + .number("(d+)") // card id + .groupEnd(",") .number("(d+),") // event .number("(d+),") // satellites .number("(d+.d+),") // odometer - .number("(d+),") // rssi - .number("(?:G(d+)|[^,]*)") // fuel + .number("(d+)") // rssi + .number(",G(d+)").optional() // fuel + .any() .compile(); private Object decodeStandard(Channel channel, SocketAddress remoteAddress, String sentence) { @@ -79,6 +90,9 @@ public class PortmanProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_TEMP + 1, parser.next()); position.set(Position.KEY_STATUS, parser.nextHexLong()); + if (parser.hasNext()) { + position.set(Position.KEY_FUEL_LEVEL, parser.nextInt() * 0.1); + } position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); int event = parser.nextInt(); @@ -159,7 +173,7 @@ public class PortmanProtocolDecoder extends BaseProtocolDecoder { Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { String sentence = (String) msg; - if (sentence.startsWith("$PTMLA")) { + if (sentence.startsWith("%%") || sentence.startsWith("$PTMLA")) { return decodeStandard(channel, remoteAddress, sentence); } else if (sentence.startsWith("$EXT")) { return decodeExtended(channel, remoteAddress, sentence); diff --git a/src/main/java/org/traccar/protocol/PositrexProtocol.java b/src/main/java/org/traccar/protocol/PositrexProtocol.java new file mode 100644 index 000000000..5cf389fbe --- /dev/null +++ b/src/main/java/org/traccar/protocol/PositrexProtocol.java @@ -0,0 +1,36 @@ +/* + * Copyright 2023 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 jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class PositrexProtocol extends BaseProtocol { + + @Inject + public PositrexProtocol(Config config) { + addServer(new TrackerServer(config, getName(), true) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new PositrexProtocolDecoder(PositrexProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java b/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java new file mode 100644 index 000000000..82ae2c134 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PositrexProtocolDecoder.java @@ -0,0 +1,116 @@ +/* + * Copyright 2023 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 org.traccar.BaseProtocolDecoder; +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 org.traccar.session.DeviceSession; + +import java.net.SocketAddress; +import java.util.Date; + +public class PositrexProtocolDecoder extends BaseProtocolDecoder { + + public PositrexProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_PING = 0x2E; + + private Date readTime(ByteBuf buf) { + long time = buf.readUnsignedInt(); + DateBuilder dateBuilder = new DateBuilder(); + dateBuilder.setSecond((int) (time % 60)); + time /= 60; + dateBuilder.setMinute((int) (time % 60)); + time /= 60; + dateBuilder.setHour((int) (time % 24)); + time /= 24; + dateBuilder.setDay((int) (time % 32)); + time /= 32; + dateBuilder.setMonth((int) (time % 13)); + dateBuilder.setYear((int) (2000 + time / 13)); + return dateBuilder.getDate(); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int first = buf.getUnsignedByte(buf.readerIndex()); + long deviceId; + if (BitUtil.check(first, 7)) { + if (BitUtil.check(first, 6)) { + deviceId = 73000000 + BitUtil.to(buf.readUnsignedInt(), 30); + } else if (!BitUtil.check(first, 5) && !BitUtil.check(first, 4)) { + deviceId = 7590000 + BitUtil.to(buf.readUnsignedMedium(), 20); + } else { + deviceId = 70000000 + BitUtil.to(buf.readUnsignedMedium(), 20); + } + } else { + deviceId = 7560000 + buf.readUnsignedShort(); + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); + if (deviceSession == null) { + return null; + } + + int service = buf.readUnsignedByte(); + if (service == MSG_PING) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(readTime(buf)); + + int latitude = buf.readMedium(); + int longitude = buf.readMedium(); + + position.setValid(BitUtil.check(latitude, 23)); + position.setLatitude(BitUtil.to(latitude, 23) * 0.000025); + position.setLongitude(longitude * 0.000025); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setCourse(buf.readUnsignedByte() * 2); + + position.set(Position.PREFIX_IO, buf.readUnsignedByte()); + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + buf.readUnsignedInt(); // report begin + buf.readUnsignedInt(); // report end + buf.readUnsignedInt(); // number of records + + if (buf.isReadable()) { + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); + } + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/PretraceProtocol.java b/src/main/java/org/traccar/protocol/PretraceProtocol.java index b77dd97bf..54a34fc69 100644 --- a/src/main/java/org/traccar/protocol/PretraceProtocol.java +++ b/src/main/java/org/traccar/protocol/PretraceProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PretraceProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PricolProtocol.java b/src/main/java/org/traccar/protocol/PricolProtocol.java index f5e904541..7b0e7386c 100644 --- a/src/main/java/org/traccar/protocol/PricolProtocol.java +++ b/src/main/java/org/traccar/protocol/PricolProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PricolProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ProgressProtocol.java b/src/main/java/org/traccar/protocol/ProgressProtocol.java index 49eb6847f..8d159ef24 100644 --- a/src/main/java/org/traccar/protocol/ProgressProtocol.java +++ b/src/main/java/org/traccar/protocol/ProgressProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ProgressProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PstProtocol.java b/src/main/java/org/traccar/protocol/PstProtocol.java index 73f978cbd..01a83b31f 100644 --- a/src/main/java/org/traccar/protocol/PstProtocol.java +++ b/src/main/java/org/traccar/protocol/PstProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class PstProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Pt215Protocol.java b/src/main/java/org/traccar/protocol/Pt215Protocol.java index b272582a4..fd67b1241 100644 --- a/src/main/java/org/traccar/protocol/Pt215Protocol.java +++ b/src/main/java/org/traccar/protocol/Pt215Protocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Pt215Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Pt3000Protocol.java b/src/main/java/org/traccar/protocol/Pt3000Protocol.java index d72774f47..5f49084ed 100644 --- a/src/main/java/org/traccar/protocol/Pt3000Protocol.java +++ b/src/main/java/org/traccar/protocol/Pt3000Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Pt3000Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Pt502Protocol.java b/src/main/java/org/traccar/protocol/Pt502Protocol.java index d5d30e8e8..0257dd60f 100644 --- a/src/main/java/org/traccar/protocol/Pt502Protocol.java +++ b/src/main/java/org/traccar/protocol/Pt502Protocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Pt502Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Pt60Protocol.java b/src/main/java/org/traccar/protocol/Pt60Protocol.java index 58345f025..83e3bfbeb 100644 --- a/src/main/java/org/traccar/protocol/Pt60Protocol.java +++ b/src/main/java/org/traccar/protocol/Pt60Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Pt60Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/PuiProtocol.java b/src/main/java/org/traccar/protocol/PuiProtocol.java new file mode 100644 index 000000000..ac8291039 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PuiProtocol.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023 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.mqtt.MqttDecoder; +import io.netty.handler.codec.mqtt.MqttEncoder; +import jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class PuiProtocol extends BaseProtocol { + + @Inject + public PuiProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(MqttEncoder.INSTANCE); + pipeline.addLast(new MqttDecoder()); + pipeline.addLast(new PuiProtocolDecoder(PuiProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/PuiProtocolDecoder.java b/src/main/java/org/traccar/protocol/PuiProtocolDecoder.java new file mode 100644 index 000000000..f10ff3fe7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PuiProtocolDecoder.java @@ -0,0 +1,73 @@ +/* + * Copyright 2023 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.mqtt.MqttPublishMessage; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import org.apache.kafka.common.utils.ByteBufferInputStream; +import org.traccar.BaseMqttProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +public class PuiProtocolDecoder extends BaseMqttProtocolDecoder { + + public PuiProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode(DeviceSession deviceSession, MqttPublishMessage message) throws Exception { + + JsonObject json; + try (ByteBufferInputStream inputStream = new ByteBufferInputStream(message.payload().nioBuffer())) { + json = Json.createReader(inputStream).readObject(); + } + + String type = json.getString("rpt"); + switch (type) { + case "hf": + case "loc": + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + position.setTime(dateFormat.parse(json.getString("ts"))); + + JsonObject location = json.getJsonObject("location"); + position.setLatitude(location.getJsonNumber("lat").doubleValue()); + position.setLongitude(location.getJsonNumber("lon").doubleValue()); + + position.setCourse(json.getInt("bear")); + position.setSpeed(UnitsConverter.knotsFromCps(json.getInt("spd"))); + + position.set(Position.KEY_IGNITION, json.getString("ign").equals("on")); + + return position; + + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/R12wProtocol.java b/src/main/java/org/traccar/protocol/R12wProtocol.java index a406f6306..b5b3eff81 100644 --- a/src/main/java/org/traccar/protocol/R12wProtocol.java +++ b/src/main/java/org/traccar/protocol/R12wProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class R12wProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java b/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java index 63ca3476c..6f7340902 100644 --- a/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java +++ b/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RaceDynamicsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RadarProtocol.java b/src/main/java/org/traccar/protocol/RadarProtocol.java index 9d88c6d72..8985e0e83 100644 --- a/src/main/java/org/traccar/protocol/RadarProtocol.java +++ b/src/main/java/org/traccar/protocol/RadarProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RadarProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RamacProtocol.java b/src/main/java/org/traccar/protocol/RamacProtocol.java new file mode 100644 index 000000000..42ce16fe8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RamacProtocol.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class RamacProtocol extends BaseProtocol { + + @Inject + public RamacProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(65535)); + pipeline.addLast(new RamacProtocolDecoder(RamacProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/RamacProtocolDecoder.java b/src/main/java/org/traccar/protocol/RamacProtocolDecoder.java new file mode 100644 index 000000000..ffdc68474 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RamacProtocolDecoder.java @@ -0,0 +1,112 @@ +/* + * Copyright 2023 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.Unpooled; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.io.StringReader; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +public class RamacProtocolDecoder extends BaseHttpProtocolDecoder { + + private final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + public RamacProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + String content = request.content().toString(StandardCharsets.UTF_8); + JsonObject json = Json.createReader(new StringReader(content)).readObject(); + + String deviceId = json.getString("DeviceId"); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, deviceId); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_TYPE, json.getInt("PacketType")); + position.set(Position.KEY_INDEX, json.getInt("SeqNumber")); + position.setDeviceTime(dateFormat.parse(json.getString("UpdateDate"))); + + int alert = json.getInt("Alert"); + if (alert > 0) { + position.set("alert", alert); + String alertMessage = json.getString("AlertMessage"); + if (!alertMessage.isEmpty()) { + position.set("alertMessage", alertMessage); + } + } + + if (json.containsKey("GpsEvent")) { + position.set("gpsEvent", json.getInt("GpsEvent")); + if (json.containsKey("GpsEventText")) { + position.set("gpsEventText", json.getString("GpsEventText")); + } + } + + if (json.containsKey("Event")) { + position.set(Position.KEY_EVENT, json.getInt("Event")); + } + if (json.containsKey("BatteryPercentage")) { + position.set(Position.KEY_BATTERY_LEVEL, json.getInt("BatteryPercentage")); + } + if (json.containsKey("Battery")) { + position.set(Position.KEY_BATTERY, json.getJsonNumber("Battery").doubleValue()); + } + + position.set("deviceType", json.getString("DeviceTypeText")); + + if (json.containsKey("Latitude") && json.containsKey("Longitude")) { + position.setValid(true); + if (json.containsKey("LocationDateTime")) { + position.setFixTime(dateFormat.parse(json.getString("LocationDateTime"))); + } else { + position.setFixTime(position.getDeviceTime()); + } + position.setLatitude(json.getJsonNumber("Latitude").doubleValue()); + position.setLongitude(json.getJsonNumber("Longitude").doubleValue()); + } else { + getLastLocation(position, position.getDeviceTime()); + } + + sendResponse( + channel, HttpResponseStatus.OK, + Unpooled.copiedBuffer("{\"CaseID\":1,\"EventID\":1}", StandardCharsets.UTF_8)); + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/RaveonProtocol.java b/src/main/java/org/traccar/protocol/RaveonProtocol.java index db70396ee..aa1a79219 100644 --- a/src/main/java/org/traccar/protocol/RaveonProtocol.java +++ b/src/main/java/org/traccar/protocol/RaveonProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RaveonProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RecodaProtocol.java b/src/main/java/org/traccar/protocol/RecodaProtocol.java index 0d50db01e..7d2fadae4 100644 --- a/src/main/java/org/traccar/protocol/RecodaProtocol.java +++ b/src/main/java/org/traccar/protocol/RecodaProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RecodaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RetranslatorProtocol.java b/src/main/java/org/traccar/protocol/RetranslatorProtocol.java index 1d4b419bb..a349a8191 100644 --- a/src/main/java/org/traccar/protocol/RetranslatorProtocol.java +++ b/src/main/java/org/traccar/protocol/RetranslatorProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RetranslatorProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RfTrackProtocol.java b/src/main/java/org/traccar/protocol/RfTrackProtocol.java index d3b41e93e..ac033c348 100644 --- a/src/main/java/org/traccar/protocol/RfTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/RfTrackProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RfTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RfTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/RfTrackProtocolDecoder.java index 28a3ac29c..cbb204e3b 100644 --- a/src/main/java/org/traccar/protocol/RfTrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RfTrackProtocolDecoder.java @@ -29,9 +29,9 @@ import org.traccar.model.Position; import org.traccar.model.WifiAccessPoint; import org.traccar.session.DeviceSession; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/traccar/protocol/RitiProtocol.java b/src/main/java/org/traccar/protocol/RitiProtocol.java index 9b9c00cb2..9916042a8 100644 --- a/src/main/java/org/traccar/protocol/RitiProtocol.java +++ b/src/main/java/org/traccar/protocol/RitiProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RitiProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RoboTrackProtocol.java b/src/main/java/org/traccar/protocol/RoboTrackProtocol.java index ab2bc5842..229c343bb 100644 --- a/src/main/java/org/traccar/protocol/RoboTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/RoboTrackProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RoboTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RstProtocol.java b/src/main/java/org/traccar/protocol/RstProtocol.java index 109d91b16..0bb809a49 100644 --- a/src/main/java/org/traccar/protocol/RstProtocol.java +++ b/src/main/java/org/traccar/protocol/RstProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RstProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java index fcc96fbf1..eafa4d3d7 100644 --- a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2024 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. @@ -69,8 +69,10 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { .number("x{4};") // sensors .number("(xx);") // status 1 .number("(xx);") // status 2 + .expression("(.*)") // additional data .groupEnd("?") .any() + .text("FIM;") .compile(); @Override @@ -115,9 +117,16 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { 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()); + + int inputs1 = parser.nextHexInt(); + int inputs2 = parser.nextHexInt(); + int inputs3 = parser.nextHexInt(); + position.set(Position.PREFIX_IN + 1, inputs1); + position.set(Position.PREFIX_IN + 2, inputs2); + position.set(Position.PREFIX_IN + 3, inputs3); + + position.set(Position.KEY_IGNITION, BitUtil.check(inputs2, 7)); + position.set(Position.PREFIX_OUT + 1, parser.nextHexInt()); position.set(Position.PREFIX_OUT + 2, parser.nextHexInt()); position.set(Position.KEY_POWER, parser.nextDouble()); @@ -125,10 +134,23 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ODOMETER, parser.nextInt()); position.set(Position.KEY_RSSI, parser.nextInt()); position.set(Position.PREFIX_TEMP + 1, (int) parser.nextHexInt().byteValue()); + position.set(Position.KEY_STATUS, (parser.nextHexInt() << 8) + parser.nextHexInt()); + + String[] values = parser.next().split(";"); + if (type == 55) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, values[0]); + } + + return position; + + } else if (type == 134) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); - int status = (parser.nextHexInt() << 8) + parser.nextHexInt(); - position.set(Position.KEY_IGNITION, BitUtil.check(status, 7)); - position.set(Position.KEY_STATUS, status); + position.set(Position.KEY_RESULT, String.valueOf(type)); return position; diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocol.java b/src/main/java/org/traccar/protocol/RuptelaProtocol.java index 99a9686f6..9f399e299 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocol.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class RuptelaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 77df0deb7..e1efb5757 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2024 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,6 +22,7 @@ import org.traccar.BaseProtocolDecoder; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; +import org.traccar.helper.BitUtil; import org.traccar.helper.DataConverter; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; @@ -50,6 +51,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_SMS_VIA_GPRS = 8; public static final int MSG_DTCS = 9; public static final int MSG_IDENTIFICATION = 15; + public static final int MSG_HEARTBEAT = 16; public static final int MSG_SET_IO = 17; public static final int MSG_FILES = 37; public static final int MSG_EXTENDED_RECORDS = 68; @@ -92,22 +94,55 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { } } + private void decodeDriver(Position position, String part1, String part2) { + Long driverIdPart1 = (Long) position.getAttributes().remove(part1); + Long driverIdPart2 = (Long) position.getAttributes().remove(part2); + if (driverIdPart1 != null && driverIdPart2 != null) { + ByteBuf driverId = Unpooled.copyLong(driverIdPart1, driverIdPart2); + position.set(Position.KEY_DRIVER_UNIQUE_ID, driverId.toString(StandardCharsets.US_ASCII)); + driverId.release(); + } + } + private void decodeParameter(Position position, int id, ByteBuf buf, int length) { switch (id) { case 2: case 3: case 4: - position.set("di" + (id - 1), readValue(buf, length, false)); - break; case 5: - position.set(Position.KEY_IGNITION, readValue(buf, length, false) == 1); + position.set(Position.PREFIX_IN + (id - 1), readValue(buf, length, false)); + break; + case 13: + case 173: + position.set(Position.KEY_MOTION, readValue(buf, length, false) > 0); + break; + case 20: + position.set(Position.PREFIX_ADC + 3, readValue(buf, length, false)); + break; + case 21: + position.set(Position.PREFIX_ADC + 4, readValue(buf, length, false)); + break; + case 22: + position.set(Position.PREFIX_ADC + 1, readValue(buf, length, false)); + break; + case 23: + position.set(Position.PREFIX_ADC + 2, readValue(buf, length, false)); break; case 29: - position.set(Position.KEY_POWER, readValue(buf, length, false)); + position.set(Position.KEY_POWER, readValue(buf, length, false) * 0.001); break; case 30: position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001); break; + case 32: + position.set(Position.KEY_DEVICE_TEMP, readValue(buf, length, true)); + break; + case 39: + position.set(Position.KEY_ENGINE_LOAD, readValue(buf, length, false)); + break; + case 65: + position.set(Position.KEY_ODOMETER, readValue(buf, length, false)); + break; case 74: position.set(Position.PREFIX_TEMP + 3, readValue(buf, length, true) * 0.1); break; @@ -116,6 +151,23 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 80: position.set(Position.PREFIX_TEMP + (id - 78), readValue(buf, length, true) * 0.1); break; + case 88: + if (readValue(buf, length, false) > 0) { + position.set(Position.KEY_ALARM, Position.ALARM_JAMMING); + } + break; + case 94: + position.set(Position.KEY_RPM, readValue(buf, length, false) * 0.25); + break; + case 95: + position.set(Position.KEY_OBD_SPEED, readValue(buf, length, false)); + break; + case 98: + position.set(Position.KEY_FUEL_LEVEL, readValue(buf, length, false) * 100 / 255.0); + break; + case 100: + position.set(Position.KEY_FUEL_CONSUMPTION, readValue(buf, length, false) / 20.0); + break; case 134: if (readValue(buf, length, false) > 0) { position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); @@ -126,9 +178,61 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); } break; + case 150: + position.set(Position.KEY_OPERATOR, readValue(buf, length, false)); + break; + case 163: + position.set(Position.KEY_ODOMETER, readValue(buf, length, false) * 5); + break; + case 164: + position.set(Position.KEY_ODOMETER_TRIP, readValue(buf, length, false) * 5); + break; + case 165: + position.set(Position.KEY_OBD_SPEED, readValue(buf, length, false) / 256.0); + break; + case 166: case 197: position.set(Position.KEY_RPM, readValue(buf, length, false) * 0.125); break; + case 170: + position.set(Position.KEY_CHARGE, readValue(buf, length, false) > 0); + break; + case 205: + position.set(Position.KEY_FUEL_LEVEL, readValue(buf, length, false)); + break; + case 207: + position.set(Position.KEY_FUEL_LEVEL, readValue(buf, length, false) * 0.4); + break; + case 208: + position.set(Position.KEY_FUEL_USED, readValue(buf, length, false) * 0.5); + break; + case 251: + case 409: + position.set(Position.KEY_IGNITION, readValue(buf, length, false) > 0); + break; + case 410: + if (readValue(buf, length, false) > 0) { + position.set(Position.KEY_ALARM, Position.ALARM_TOW); + } + break; + case 411: + if (readValue(buf, length, false) > 0) { + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); + } + break; + case 415: + if (readValue(buf, length, false) == 0) { + position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); + } + break; + case 645: + position.set(Position.KEY_OBD_ODOMETER, readValue(buf, length, false) * 1000); + break; + case 758: + if (readValue(buf, length, false) == 1) { + position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING); + } + break; default: position.set(Position.PREFIX_IO + id, readValue(buf, length, false)); break; @@ -166,22 +270,36 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // timestamp extension if (type == MSG_EXTENDED_RECORDS) { - buf.readUnsignedByte(); // record extension + int recordExtension = buf.readUnsignedByte(); + int mergeRecordCount = BitUtil.from(recordExtension, 4); + int currentRecord = BitUtil.to(recordExtension, 4); + + if (currentRecord > 0 && currentRecord <= mergeRecordCount) { + if (positions.size() == 0) { + getLastLocation(position, null); + } else { + position = positions.remove(positions.size() - 1); + } + } } buf.readUnsignedByte(); // priority (reserved) - position.setValid(true); - position.setLongitude(buf.readInt() / 10000000.0); - position.setLatitude(buf.readInt() / 10000000.0); - position.setAltitude(buf.readUnsignedShort() / 10.0); - position.setCourse(buf.readUnsignedShort() / 100.0); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - - position.set(Position.KEY_HDOP, buf.readUnsignedByte() / 10.0); + int longitude = buf.readInt(); + int latitude = buf.readInt(); + if (longitude > Integer.MIN_VALUE && latitude > Integer.MIN_VALUE) { + position.setValid(true); + position.setLongitude(longitude / 10000000.0); + position.setLatitude(latitude / 10000000.0); + position.setAltitude(buf.readUnsignedShort() / 10.0); + position.setCourse(buf.readUnsignedShort() / 100.0); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + position.set(Position.KEY_HDOP, buf.readUnsignedByte() / 10.0); + } else { + buf.skipBytes(8); + getLastLocation(position, null); + } if (type == MSG_EXTENDED_RECORDS) { position.set(Position.KEY_EVENT, buf.readUnsignedShort()); @@ -217,12 +335,13 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { decodeParameter(position, id, buf, 8); } - Long driverIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 126); - Long driverIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 127); - if (driverIdPart1 != null && driverIdPart2 != null) { - ByteBuf driverId = Unpooled.copyLong(driverIdPart1, driverIdPart2); - position.set(Position.KEY_DRIVER_UNIQUE_ID, driverId.toString(StandardCharsets.US_ASCII)); - driverId.release(); + decodeDriver(position, Position.PREFIX_IO + 126, Position.PREFIX_IO + 127); // can driver + decodeDriver(position, Position.PREFIX_IO + 155, Position.PREFIX_IO + 156); // tco driver + + Long tagIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760); + Long tagIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761); + if (tagIdPart1 != null && tagIdPart2 != null) { + position.set("tagId", Long.toHexString(tagIdPart1) + Long.toHexString(tagIdPart2)); } positions.add(position); @@ -306,7 +425,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { return null; - } else if (type == MSG_IDENTIFICATION) { + } else if (type == MSG_IDENTIFICATION || type == MSG_HEARTBEAT) { ByteBuf content = Unpooled.buffer(); content.writeByte(1); diff --git a/src/main/java/org/traccar/protocol/S168Protocol.java b/src/main/java/org/traccar/protocol/S168Protocol.java index f904ed9ff..5fb0c6e72 100644 --- a/src/main/java/org/traccar/protocol/S168Protocol.java +++ b/src/main/java/org/traccar/protocol/S168Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class S168Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SabertekProtocol.java b/src/main/java/org/traccar/protocol/SabertekProtocol.java index 403243cdc..cb3f2ab32 100644 --- a/src/main/java/org/traccar/protocol/SabertekProtocol.java +++ b/src/main/java/org/traccar/protocol/SabertekProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SabertekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SanavProtocol.java b/src/main/java/org/traccar/protocol/SanavProtocol.java index 1a0e7b0e9..ac1941725 100644 --- a/src/main/java/org/traccar/protocol/SanavProtocol.java +++ b/src/main/java/org/traccar/protocol/SanavProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SanavProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SanulProtocol.java b/src/main/java/org/traccar/protocol/SanulProtocol.java index ea44bf868..cba162296 100644 --- a/src/main/java/org/traccar/protocol/SanulProtocol.java +++ b/src/main/java/org/traccar/protocol/SanulProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SanulProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SatsolProtocol.java b/src/main/java/org/traccar/protocol/SatsolProtocol.java index d90033e38..7252f99f0 100644 --- a/src/main/java/org/traccar/protocol/SatsolProtocol.java +++ b/src/main/java/org/traccar/protocol/SatsolProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SatsolProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocol.java b/src/main/java/org/traccar/protocol/SigfoxProtocol.java index 9a268af62..edd624727 100644 --- a/src/main/java/org/traccar/protocol/SigfoxProtocol.java +++ b/src/main/java/org/traccar/protocol/SigfoxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SigfoxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java index 4ed2bb51d..e0dfab9b2 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 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2024 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,11 +32,11 @@ import org.traccar.model.Network; import org.traccar.model.Position; import org.traccar.model.WifiAccessPoint; -import javax.json.Json; -import javax.json.JsonNumber; -import javax.json.JsonObject; -import javax.json.JsonString; -import javax.json.JsonValue; +import jakarta.json.Json; +import jakarta.json.JsonNumber; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; import java.io.StringReader; import java.net.SocketAddress; import java.net.URLDecoder; @@ -105,7 +105,7 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { FullHttpRequest request = (FullHttpRequest) msg; String content = request.content().toString(StandardCharsets.UTF_8); if (!content.startsWith("{")) { - content = URLDecoder.decode(content.split("=")[0], "UTF-8"); + content = URLDecoder.decode(content.split("=")[0], StandardCharsets.UTF_8); } JsonObject json = Json.createReader(new StringReader(content)).readObject(); @@ -156,18 +156,30 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(json.getString("data"))); try { - int event = buf.readUnsignedByte(); - if (event == 0x0f || event == 0x1f) { + int header = buf.readUnsignedByte(); + if ("Amber".equals(getDeviceModel(deviceSession))) { + + int flags = buf.readUnsignedByte(); + position.set(Position.KEY_MOTION, BitUtil.check(flags, 1)); + + position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.02); + position.set(Position.PREFIX_TEMP + 1, (int) buf.readByte()); + + position.setValid(true); + position.setLatitude(buf.readInt() / 60000.0); + position.setLongitude(buf.readInt() / 60000.0); + + } else if (header == 0x0f || header == 0x1f) { - position.setValid(event >> 4 > 0); + position.setValid(header >> 4 > 0); position.setLatitude(BufferUtil.readSignedMagnitudeInt(buf) * 0.000001); position.setLongitude(BufferUtil.readSignedMagnitudeInt(buf) * 0.000001); position.set(Position.KEY_BATTERY, (int) buf.readUnsignedByte()); - } else if (event >> 4 <= 3 && buf.writerIndex() == 12) { + } else if (header >> 4 <= 3 && buf.writerIndex() == 12) { - if (BitUtil.to(event, 4) == 0) { + if (BitUtil.to(header, 4) == 0) { position.setValid(true); position.setLatitude(buf.readIntLE() * 0.0000001); position.setLongitude(buf.readIntLE() * 0.0000001); diff --git a/src/main/java/org/traccar/protocol/SiwiProtocol.java b/src/main/java/org/traccar/protocol/SiwiProtocol.java index f12958a50..59b96bf72 100644 --- a/src/main/java/org/traccar/protocol/SiwiProtocol.java +++ b/src/main/java/org/traccar/protocol/SiwiProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SiwiProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SkypatrolProtocol.java b/src/main/java/org/traccar/protocol/SkypatrolProtocol.java index 7ae26f634..615ef536d 100644 --- a/src/main/java/org/traccar/protocol/SkypatrolProtocol.java +++ b/src/main/java/org/traccar/protocol/SkypatrolProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SkypatrolProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SmartSoleProtocol.java b/src/main/java/org/traccar/protocol/SmartSoleProtocol.java index cb7efb7ee..e4838581a 100644 --- a/src/main/java/org/traccar/protocol/SmartSoleProtocol.java +++ b/src/main/java/org/traccar/protocol/SmartSoleProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SmartSoleProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SmokeyProtocol.java b/src/main/java/org/traccar/protocol/SmokeyProtocol.java index 22b343537..0aa2bcfa7 100644 --- a/src/main/java/org/traccar/protocol/SmokeyProtocol.java +++ b/src/main/java/org/traccar/protocol/SmokeyProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SmokeyProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java b/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java index 0676aa629..e00f27b9b 100644 --- a/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java +++ b/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SolarPoweredProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SpotProtocol.java b/src/main/java/org/traccar/protocol/SpotProtocol.java index 6bd802fed..4fc57f177 100644 --- a/src/main/java/org/traccar/protocol/SpotProtocol.java +++ b/src/main/java/org/traccar/protocol/SpotProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SpotProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocol.java b/src/main/java/org/traccar/protocol/StarLinkProtocol.java index d578fa705..6dcd40fbf 100644 --- a/src/main/java/org/traccar/protocol/StarLinkProtocol.java +++ b/src/main/java/org/traccar/protocol/StarLinkProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class StarLinkProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java index aa23bfac5..193005e28 100644 --- a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java @@ -61,10 +61,10 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder { @Override protected void init() { setFormat(getConfig().getString( - getProtocolName() + ".format", "#EDT#,#EID#,#PDT#,#LAT#,#LONG#,#SPD#,#HEAD#,#ODO#," + Keys.PROTOCOL_FORMAT.withPrefix(getProtocolName()), "#EDT#,#EID#,#PDT#,#LAT#,#LONG#,#SPD#,#HEAD#,#ODO#," + "#IN1#,#IN2#,#IN3#,#IN4#,#OUT1#,#OUT2#,#OUT3#,#OUT4#,#LAC#,#CID#,#VIN#,#VBAT#,#DEST#,#IGN#,#ENG#")); - setDateFormat(getConfig().getString(getProtocolName() + ".dateFormat", "yyMMddHHmmss")); + setDateFormat(getConfig().getString(Keys.PROTOCOL_DATE_FORMAT.withPrefix(getProtocolName()), "yyMMddHHmmss")); } public String[] getFormat(long deviceId) { diff --git a/src/main/java/org/traccar/protocol/StarcomProtocol.java b/src/main/java/org/traccar/protocol/StarcomProtocol.java index 33c3a4776..458220e59 100644 --- a/src/main/java/org/traccar/protocol/StarcomProtocol.java +++ b/src/main/java/org/traccar/protocol/StarcomProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class StarcomProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java index 56ab733c8..325847b16 100644 --- a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java @@ -75,7 +75,7 @@ public class StarcomProtocolDecoder extends BaseProtocolDecoder { case "eventid": position.set(Position.KEY_EVENT, Integer.parseInt(value)); break; - case "mileage": + case "odometer": position.set(Position.KEY_ODOMETER, (long) (Double.parseDouble(value) * 1000)); break; case "satellites": @@ -110,8 +110,8 @@ public class StarcomProtocolDecoder extends BaseProtocolDecoder { case "extra1": case "extra2": case "extra3": - position.set(key, value); default: + position.set(key, value); break; } } diff --git a/src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java b/src/main/java/org/traccar/protocol/StartekFrameDecoder.java index 5b610013a..608b128cd 100644 --- a/src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java +++ b/src/main/java/org/traccar/protocol/StartekFrameDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2024 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,13 +20,30 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import org.traccar.BaseFrameDecoder; -public class NdtpV6FrameDecoder extends BaseFrameDecoder { +import java.nio.charset.StandardCharsets; + +public class StartekFrameDecoder extends BaseFrameDecoder { @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - return buf; + if (buf.readableBytes() < 10) { + return null; + } + + int lengthIndex = buf.readerIndex() + 3; + int dividerIndex = buf.indexOf(lengthIndex, buf.writerIndex(), (byte) ','); + if (dividerIndex > 0) { + int lengthOffset = dividerIndex - buf.readerIndex() + 4; + int length = lengthOffset + Integer.parseInt(buf.getCharSequence( + lengthIndex, dividerIndex - lengthIndex, StandardCharsets.US_ASCII).toString()); + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + } + + return null; } } diff --git a/src/main/java/org/traccar/protocol/StartekProtocol.java b/src/main/java/org/traccar/protocol/StartekProtocol.java index d010df858..9c01d24e2 100644 --- a/src/main/java/org/traccar/protocol/StartekProtocol.java +++ b/src/main/java/org/traccar/protocol/StartekProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 2024 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. @@ -15,7 +15,6 @@ */ 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; @@ -24,7 +23,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class StartekProtocol extends BaseProtocol { @@ -38,7 +37,7 @@ public class StartekProtocol extends BaseProtocol { addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StartekFrameDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); pipeline.addLast(new StartekProtocolEncoder(StartekProtocol.this)); diff --git a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java index 8e3624cb5..0eeb5b2aa 100644 --- a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 2024 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. @@ -41,12 +41,13 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { .expression(".") // index .number("d+,") // length .number("(d+),") // imei + .number("(xxx),") // type .expression("(.+)") // content .number("xx") // checksum + .text("\r\n") .compile(); private static final Pattern PATTERN_POSITION = new PatternBuilder() - .number("xxx,") // command .number("(d+),") // event .expression("([^,]+)?,") // event data .number("(dd)(dd)(dd)") // date (yyymmdd) @@ -72,12 +73,10 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { .number("(x+)") // battery .expression("([^,]+)?") // adc .groupBegin() - .text(",") - .number("d,") // extended - .expression("([^,]+)?") // fuel + .number(",d+") // extended + .expression(",([^,]+)?") // fuel .groupBegin() - .text(",") - .expression("([^,]+)?") // temperature + .expression(",([^,]+)?") // temperature .groupBegin() .text(",") .groupBegin() @@ -91,16 +90,26 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { .number("(d+)?|") // instant fuel .number("(d+)[%L]").optional() // fuel level .groupEnd("?") + .number(",(d+)").optional() // hours .groupEnd("?") .groupEnd("?") .groupEnd("?") + .any() .compile(); private String decodeAlarm(int value) { switch (value) { + case 1: + return Position.ALARM_SOS; case 5: case 6: return Position.ALARM_DOOR; + case 17: + return Position.ALARM_LOW_POWER; + case 18: + return Position.ALARM_POWER_CUT; + case 19: + return Position.ALARM_POWER_RESTORED; case 39: return Position.ALARM_ACCELERATION; case 40: @@ -126,26 +135,24 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { return null; } + String type = parser.next(); String content = parser.next(); - if (content.length() < 100) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - position.set(Position.KEY_RESULT, content); - - return position; - - } else { - - return decodePosition(deviceSession, content); - + switch (type) { + case "000": + return decodePosition(deviceSession, content); + case "710": + return decodeSerial(deviceSession, content); + default: + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + getLastLocation(position, null); + position.set(Position.KEY_TYPE, type); + position.set(Position.KEY_RESULT, content); + return position; } } - protected Object decodePosition(DeviceSession deviceSession, String content) throws Exception { + private Object decodePosition(DeviceSession deviceSession, String content) { Parser parser = new Parser(PATTERN_POSITION, content); if (!parser.matches()) { @@ -176,7 +183,7 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { position.setCourse(parser.nextInt()); position.setAltitude(parser.nextInt()); - position.set(Position.KEY_ODOMETER, parser.nextInt()); + position.set(Position.KEY_ODOMETER, parser.nextLong()); position.setNetwork(new Network(CellTower.from( parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt(), parser.nextInt()))); @@ -186,6 +193,7 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { int input = parser.nextHexInt(); int output = parser.nextHexInt(); position.set(Position.KEY_IGNITION, BitUtil.check(input, 1)); + position.set(Position.KEY_DOOR, BitUtil.check(input, 2)); position.set(Position.KEY_INPUT, input); position.set(Position.KEY_OUTPUT, output); @@ -221,7 +229,7 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { } } - if (parser.hasNext(6)) { + if (parser.hasNextAny(9)) { position.set(Position.KEY_RPM, parser.nextInt()); position.set(Position.KEY_ENGINE_LOAD, parser.nextInt()); position.set("airFlow", parser.nextInt()); @@ -239,6 +247,87 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); } + if (parser.hasNext()) { + position.set(Position.KEY_HOURS, parser.nextInt() * 1000L); + } + + return position; + } + + private Object decodeSerial(DeviceSession deviceSession, String content) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + String[] frames = content.split("\r\n"); + + for (String frame : frames) { + String[] values = frame.split(","); + int index = 0; + String type = values[index++]; + switch (type) { + case "T1": + index += 1; // speed + position.set(Position.KEY_RPM, Double.parseDouble(values[index++])); + index += 1; // fuel consumption + position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(values[index++])); + index += 4; // axel weights + index += 1; // turbo pressure + position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(values[index++])); + index += 1; // accelerator pedal + position.set("torque", Integer.parseInt(values[index++])); + index += 1; // firmware version + position.set(Position.KEY_POWER, Double.parseDouble(values[index++])); + index += 1; // coolant level + position.set("oilTemp", Double.parseDouble(values[index++])); + index += 1; // oil level + position.set(Position.KEY_THROTTLE, Double.parseDouble(values[index++])); + index += 1; // air inlet pressure + index += 1; // fuel tank secondary + index += 1; // current gear + index += 1; // seatbelt + position.set("oilPressure", Integer.parseInt(values[index++])); + index += 1; // wet tank air pressure + index += 1; // pto state + int ignition = Integer.parseInt(values[index++]); + if (ignition < 2) { + position.set(Position.KEY_IGNITION, ignition > 0); + } + index += 1; // brake pedal + position.set("catalystLevel", Double.parseDouble(values[index++])); + index += 1; // fuel type + break; + case "T2": + position.set(Position.KEY_ODOMETER, Double.parseDouble(values[index++]) * 1000); + index += 1; // total fuel + index += 1; // fuel used cruise + index += 1; // fuel used drive + index += 1; + index += 1; + index += 1; // total idle time + index += 1; // total time pto + index += 1; // time cruise + index += 1; + index += 1; + index += 1; + index += 1; + index += 1; + index += 1; // brake apps + index += 1; // clutch apps + position.set(Position.KEY_HOURS, Integer.parseInt(values[index++])); + index += 1; // time torque + position.set(Position.KEY_FUEL_CONSUMPTION, Double.parseDouble(values[index++])); + index += 1; // total cruise control distance + position.set(Position.KEY_FUEL_USED, Double.parseDouble(values[index++])); + index += 1; // total drive time + break; + default: + break; + } + } + return position; } diff --git a/src/main/java/org/traccar/protocol/StbProtocol.java b/src/main/java/org/traccar/protocol/StbProtocol.java index af4e0d2c4..0beaed39c 100644 --- a/src/main/java/org/traccar/protocol/StbProtocol.java +++ b/src/main/java/org/traccar/protocol/StbProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class StbProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/StbProtocolDecoder.java b/src/main/java/org/traccar/protocol/StbProtocolDecoder.java index 641359bfd..c52ab485f 100644 --- a/src/main/java/org/traccar/protocol/StbProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StbProtocolDecoder.java @@ -22,9 +22,9 @@ import org.traccar.Protocol; import org.traccar.model.Position; import org.traccar.session.DeviceSession; -import javax.json.Json; -import javax.json.JsonObject; -import javax.json.JsonValue; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; import java.io.StringReader; import java.net.SocketAddress; import java.util.Date; diff --git a/src/main/java/org/traccar/protocol/Stl060Protocol.java b/src/main/java/org/traccar/protocol/Stl060Protocol.java index 83b5db3bb..ac23ab3ee 100644 --- a/src/main/java/org/traccar/protocol/Stl060Protocol.java +++ b/src/main/java/org/traccar/protocol/Stl060Protocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Stl060Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SuntechProtocol.java b/src/main/java/org/traccar/protocol/SuntechProtocol.java index 4253b761b..0cc5fc75c 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocol.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SuntechProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java index 047a1822a..53c4a5d02 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java @@ -271,18 +271,26 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { index += 1; // collaborative network } - DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - position.setTime(dateFormat.parse(values[index++] + values[index++])); + if (values[index].isEmpty()) { - position.setLatitude(Double.parseDouble(values[index++])); - position.setLongitude(Double.parseDouble(values[index++])); - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); - position.setCourse(Double.parseDouble(values[index++])); + getLastLocation(position, null); - position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); + } else { - position.setValid(values[index++].equals("1")); + DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + position.setTime(dateFormat.parse(values[index++] + values[index++])); + + position.setLatitude(Double.parseDouble(values[index++])); + position.setLongitude(Double.parseDouble(values[index++])); + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); + position.setCourse(Double.parseDouble(values[index++])); + + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); + + position.setValid(values[index++].equals("1")); + + } return position; } @@ -446,9 +454,10 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { if (values.length - index >= 2) { String driverUniqueId = values[index++]; - if (values[index++].equals("1") && !driverUniqueId.isEmpty()) { + if (!driverUniqueId.isEmpty()) { position.set(Position.KEY_DRIVER_UNIQUE_ID, driverUniqueId); } + index += 1; // registered } if (isIncludeTemp(deviceSession.getDeviceId())) { diff --git a/src/main/java/org/traccar/protocol/SupermateProtocol.java b/src/main/java/org/traccar/protocol/SupermateProtocol.java index 4290b7126..064f12b4b 100644 --- a/src/main/java/org/traccar/protocol/SupermateProtocol.java +++ b/src/main/java/org/traccar/protocol/SupermateProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SupermateProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SviasProtocol.java b/src/main/java/org/traccar/protocol/SviasProtocol.java index 7c6624f7c..a903d503c 100644 --- a/src/main/java/org/traccar/protocol/SviasProtocol.java +++ b/src/main/java/org/traccar/protocol/SviasProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SviasProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/SwiftechProtocol.java b/src/main/java/org/traccar/protocol/SwiftechProtocol.java index 68cf40d84..d5fa5c5d3 100644 --- a/src/main/java/org/traccar/protocol/SwiftechProtocol.java +++ b/src/main/java/org/traccar/protocol/SwiftechProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class SwiftechProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/T55Protocol.java b/src/main/java/org/traccar/protocol/T55Protocol.java index cedac275f..e76959fea 100644 --- a/src/main/java/org/traccar/protocol/T55Protocol.java +++ b/src/main/java/org/traccar/protocol/T55Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class T55Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java index 3be161fb8..9e7518ce5 100644 --- a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2023 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. @@ -41,7 +41,8 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { } private static final Pattern PATTERN_GPRMC = new PatternBuilder() - .text("$GPRMC,") + .text("$") + .expression("G[PLN]RMC,") .number("(dd)(dd)(dd).?d*,") // time (hhmmss) .expression("([AV]),") // validity .number("(dd)(dd.d+),") // latitude @@ -64,7 +65,8 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { .compile(); private static final Pattern PATTERN_GPGGA = new PatternBuilder() - .text("$GPGGA,") + .text("$") + .expression("G[PLN]GGA,") .number("(dd)(dd)(dd).?d*,") // time (hhmmss) .number("(d+)(dd.d+),") // latitude .expression("([NS]),") @@ -150,6 +152,18 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { .number("xx") // checksum .compile(); + private static final Pattern PATTERN_GPTXT = new PatternBuilder() + .text("$GPTXT,") + .text("NET,") + .number("(d+),") // device id + .expression("([^,]+),") // network operator + .number("(-d+),") // rssi + .number("(d+) ") // mcc + .number("(d+)") // mnc + .text("*") + .number("xx") // checksum + .compile(); + private Position position = null; private Position decodeGprmc( @@ -328,6 +342,31 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { return position; } + private Position decodeGptxt(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_GPTXT, 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_OPERATOR, parser.next()); + position.set(Position.KEY_RSSI, parser.nextInt()); + position.set("mcc", parser.nextInt()); + position.set("mnc", parser.nextInt()); + + return position; + } + private Position decodePubx(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_PUBX, sentence); @@ -407,9 +446,9 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { } } else if (sentence.matches("^[0-9A-F]+$")) { getDeviceSession(channel, remoteAddress, sentence); - } else if (sentence.startsWith("$GPRMC")) { + } else if (sentence.startsWith("RMC", 3)) { return decodeGprmc(deviceSession, sentence, remoteAddress, channel); - } else if (sentence.startsWith("$GPGGA") && deviceSession != null) { + } else if (sentence.startsWith("GGA", 3) && deviceSession != null) { return decodeGpgga(deviceSession, sentence); } else if (sentence.startsWith("$GPRMA") && deviceSession != null) { return decodeGprma(deviceSession, sentence); @@ -421,6 +460,8 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { return decodeQze(channel, remoteAddress, sentence); } else if (sentence.startsWith("$PUBX")) { return decodePubx(channel, remoteAddress, sentence); + } else if (sentence.startsWith("$GPTXT")) { + return decodeGptxt(channel, remoteAddress, sentence); } return null; diff --git a/src/main/java/org/traccar/protocol/T57Protocol.java b/src/main/java/org/traccar/protocol/T57Protocol.java index 4bafe8c6d..e6ef4ccc9 100644 --- a/src/main/java/org/traccar/protocol/T57Protocol.java +++ b/src/main/java/org/traccar/protocol/T57Protocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class T57Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/T622IridiumProtocol.java b/src/main/java/org/traccar/protocol/T622IridiumProtocol.java new file mode 100644 index 000000000..22efa38a8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/T622IridiumProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023 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.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +import jakarta.inject.Inject; + +public class T622IridiumProtocol extends BaseProtocol { + + @Inject + public T622IridiumProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1, 2)); + pipeline.addLast(new T622IridiumProtocolDecoder(T622IridiumProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java b/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java new file mode 100644 index 000000000..9e64ec9be --- /dev/null +++ b/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java @@ -0,0 +1,149 @@ +/* + * Copyright 2023 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 org.traccar.BaseProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.config.Keys; +import org.traccar.helper.UnitsConverter; +import org.traccar.helper.model.AttributeUtil; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +public class T622IridiumProtocolDecoder extends BaseProtocolDecoder { + + private String format; + + public T622IridiumProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public List<Integer> getParameters(long deviceId) { + String value = AttributeUtil.lookup( + getCacheManager(), Keys.PROTOCOL_FORMAT.withPrefix(getProtocolName()), deviceId); + return Arrays.stream((value != null ? value : format).split(",")) + .map(s -> Integer.parseInt(s, 16)) + .collect(Collectors.toList()); + } + + public void setFormat(String format) { + this.format = format; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // protocol revision + buf.readUnsignedShort(); // length + buf.readUnsignedByte(); // header indicator + buf.readUnsignedShort(); // header length + buf.readUnsignedInt(); // reference + + String imei = buf.readCharSequence(15, StandardCharsets.US_ASCII).toString(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + buf.readUnsignedByte(); // session status + buf.readUnsignedShort(); // originator index + buf.readUnsignedShort(); // transfer index + buf.readUnsignedInt(); // session time + buf.readUnsignedByte(); // payload indicator + buf.readUnsignedShort(); // payload length + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + List<Integer> parameters = getParameters(deviceSession.getDeviceId()); + + for (int parameter : parameters) { + switch (parameter) { + case 0x01: + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + break; + case 0x02: + position.setLatitude(buf.readIntLE() / 1000000.0); + break; + case 0x03: + position.setLongitude(buf.readIntLE() / 1000000.0); + break; + case 0x04: + position.setTime(new Date((buf.readUnsignedIntLE() + 946684800) * 1000)); + break; + case 0x05: + position.setValid(buf.readUnsignedByte() > 0); + break; + case 0x06: + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + break; + case 0x07: + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + break; + case 0x08: + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); + break; + case 0x09: + position.setCourse(buf.readUnsignedShortLE()); + break; + case 0x0A: + position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); + break; + case 0x0B: + position.setAltitude(buf.readShortLE()); + break; + case 0x0C: + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + break; + case 0x0D: + position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 1000); + break; + case 0x14: + position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); + break; + case 0x15: + position.set(Position.KEY_INPUT, buf.readUnsignedByte()); + break; + case 0x19: + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); + break; + case 0x1A: + position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.01); + break; + case 0x1B: + buf.readUnsignedByte(); // geofence + break; + default: + break; + } + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/T800xProtocol.java b/src/main/java/org/traccar/protocol/T800xProtocol.java index 253c3cb73..f50f22a18 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocol.java +++ b/src/main/java/org/traccar/protocol/T800xProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class T800xProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java index 6e09e6e3b..23750be8d 100644 --- a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2023 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,8 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.config.Keys; +import org.traccar.helper.model.AttributeUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -161,7 +163,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { boolean positionType = type == MSG_GPS || type == MSG_GPS_2 || type == MSG_ALARM || type == MSG_ALARM_2; if (!positionType) { - sendResponse(channel, header, type, index, imei, 0); + sendResponse(channel, header, type, header == 0x2323 ? 1 : index, imei, 0); } if (positionType) { @@ -389,7 +391,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { for (int i = 1; i <= adcCount; i++) { String value = ByteBufUtil.hexDump(buf.readSlice(2)); if (!value.equals("ffff")) { - position.set(Position.PREFIX_ADC + i, Integer.parseInt(value) * 0.01); + position.set(Position.PREFIX_ADC + i, Integer.parseInt(value, 16) * 0.01); } } } @@ -398,6 +400,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { int alarm = buf.readUnsignedByte(); position.set(Position.KEY_ALARM, header != 0x2727 ? decodeAlarm1(alarm) : decodeAlarm2(alarm)); + position.set("alarmCode", alarm); if (header != 0x2727) { @@ -468,6 +471,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { int inputStatus = buf.readUnsignedShort(); position.set(Position.KEY_IGNITION, BitUtil.check(inputStatus, 2)); position.set(Position.KEY_RSSI, BitUtil.between(inputStatus, 4, 11)); + position.set(Position.KEY_INPUT, inputStatus); buf.readUnsignedShort(); // ignition on upload interval buf.readUnsignedInt(); // ignition off upload interval @@ -511,8 +515,10 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder { } } - if (type == MSG_ALARM || type == MSG_ALARM_2) { - sendResponse(channel, header, type, index, imei, alarm); + boolean acknowledgement = AttributeUtil.lookup( + getCacheManager(), Keys.PROTOCOL_ACK.withPrefix(getProtocolName()), deviceSession.getDeviceId()); + if (acknowledgement || type == MSG_ALARM || type == MSG_ALARM_2) { + sendResponse(channel, header, type, header == 0x2323 ? 1 : index, imei, alarm); } return position; diff --git a/src/main/java/org/traccar/protocol/TaipPrefixEncoder.java b/src/main/java/org/traccar/protocol/TaipPrefixEncoder.java index 48419af2a..75fd447d0 100644 --- a/src/main/java/org/traccar/protocol/TaipPrefixEncoder.java +++ b/src/main/java/org/traccar/protocol/TaipPrefixEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 2023 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. @@ -15,40 +15,20 @@ */ package org.traccar.protocol; -import com.google.inject.Inject; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageEncoder; -import org.traccar.Protocol; -import org.traccar.config.Config; -import org.traccar.config.Keys; import java.util.List; @ChannelHandler.Sharable public class TaipPrefixEncoder extends MessageToMessageEncoder<ByteBuf> { - private final Protocol protocol; - private Config config; - - public TaipPrefixEncoder(Protocol protocol) { - this.protocol = protocol; - } - - @Inject - public void setConfig(Config config) { - this.config = config; - } - @Override protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) { - if (config.getBoolean(Keys.PROTOCOL_PREFIX.withPrefix(protocol.getName()))) { - out.add(Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(new byte[] {0x20, 0x20, 0x06, 0x00}), msg.retain())); - } else { - out.add(msg.retain()); - } + out.add(Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(new byte[] {0x20, 0x20, 0x06, 0x00}), msg.retain())); } } diff --git a/src/main/java/org/traccar/protocol/TaipProtocol.java b/src/main/java/org/traccar/protocol/TaipProtocol.java index 943ec98c5..f57bb296c 100644 --- a/src/main/java/org/traccar/protocol/TaipProtocol.java +++ b/src/main/java/org/traccar/protocol/TaipProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2023 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,7 +23,8 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; +import org.traccar.config.Keys; public class TaipProtocol extends BaseProtocol { @@ -33,7 +34,9 @@ public class TaipProtocol extends BaseProtocol { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '<')); - pipeline.addLast(new TaipPrefixEncoder(TaipProtocol.this)); + if (config.getBoolean(Keys.PROTOCOL_PREFIX.withPrefix(getName()))) { + pipeline.addLast(new TaipPrefixEncoder()); + } pipeline.addLast(new StringDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new TaipProtocolDecoder(TaipProtocol.this)); @@ -42,7 +45,9 @@ public class TaipProtocol extends BaseProtocol { addServer(new TrackerServer(config, getName(), true) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { - pipeline.addLast(new TaipPrefixEncoder(TaipProtocol.this)); + if (config.getBoolean(Keys.PROTOCOL_PREFIX.withPrefix(getName()))) { + pipeline.addLast(new TaipPrefixEncoder()); + } pipeline.addLast(new StringDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new TaipProtocolDecoder(TaipProtocol.this)); diff --git a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java index e5e84b7c4..448d7ffca 100644 --- a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2023 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,7 +26,6 @@ import org.traccar.helper.DateBuilder; import org.traccar.helper.DateUtil; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; import java.net.SocketAddress; @@ -49,7 +48,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { .groupEnd("?") .number("(d{5})") // seconds .or() - .expression("(?:RGP|RCQ|RCV|RBR|RUS00),?") // type + .expression("(?:RGP|RCQ|RCV|RBR|RUS00|RPI),?") // type .number("(dd)?") // event .number("(dd)(dd)(dd)") // date (mmddyy) .number("(dd)(dd)(dd)") // time (hhmmss) @@ -84,7 +83,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { .or() .groupBegin() .number("(xx)") // input - .number("(xx)") // satellites + .number("xx") // satellites / outputs .number("(ddd)") // battery .number("(x{8})") // odometer .number("[01]") // gps power @@ -96,12 +95,14 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { .number("[01]") // modem power .number("[0-5]") // gsm status .number("(dd)") // rssi + .groupBegin() .number("([-+]dddd)") // temperature 1 .number("xx") // seconds from last .number("([-+]dddd)") // temperature 2 .number("xx") // seconds from last .groupEnd("?") .groupEnd("?") + .groupEnd("?") .groupEnd() .any() .compile(); @@ -192,7 +193,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); } - position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble(0))); + position.setSpeed(convertSpeed(parser.nextDouble(0), "mph")); position.setCourse(parser.nextDouble(0)); if (parser.hasNext(2)) { @@ -217,17 +218,18 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_HDOP, parser.nextInt()); } - if (parser.hasNext(4)) { + if (parser.hasNext(3)) { position.set(Position.KEY_INPUT, parser.nextHexInt(0)); - position.set(Position.KEY_SATELLITES, parser.nextHexInt(0)); position.set(Position.KEY_BATTERY, parser.nextInt(0)); position.set(Position.KEY_ODOMETER, parser.nextLong(16, 0)); } - if (parser.hasNext(4)) { + if (parser.hasNext(3)) { valid = parser.nextInt() > 0; position.set(Position.KEY_PDOP, parser.nextInt()); position.set(Position.KEY_RSSI, parser.nextInt()); + } + if (parser.hasNext(2)) { position.set(Position.PREFIX_TEMP + 1, parser.nextInt() * 0.01); position.set(Position.PREFIX_TEMP + 2, parser.nextInt() * 0.01); } @@ -262,6 +264,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { String uniqueId = null; DeviceSession deviceSession = null; String messageIndex = null; + boolean indexFirst = true; if (attributes != null) { for (String attribute : attributes) { @@ -276,6 +279,9 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { if (deviceSession != null) { position.setDeviceId(deviceSession.getDeviceId()); } + if (messageIndex == null) { + indexFirst = false; + } break; case "io": position.set(Position.KEY_IGNITION, BitUtil.check(value.charAt(0) - '0', 0)); @@ -315,7 +321,11 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { if (messageIndex.startsWith("#IP")) { response = ">SAK;ID=" + uniqueId + ";" + messageIndex + "<"; } else { - response = ">ACK;ID=" + uniqueId + ";" + messageIndex + ";*"; + if (indexFirst) { + response = ">ACK;" + messageIndex + ";ID=" + uniqueId + ";*"; + } else { + response = ">ACK;ID=" + uniqueId + ";" + messageIndex + ";*"; + } response += String.format("%02X", Checksum.xor(response)) + "<"; } channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); diff --git a/src/main/java/org/traccar/protocol/TechTltProtocol.java b/src/main/java/org/traccar/protocol/TechTltProtocol.java index 191dd9ccc..a4a7460b0 100644 --- a/src/main/java/org/traccar/protocol/TechTltProtocol.java +++ b/src/main/java/org/traccar/protocol/TechTltProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TechTltProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java b/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java index 265a3eb64..f0828a99e 100644 --- a/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java +++ b/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TechtoCruzProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TekProtocol.java b/src/main/java/org/traccar/protocol/TekProtocol.java index 54e860d79..56714041b 100644 --- a/src/main/java/org/traccar/protocol/TekProtocol.java +++ b/src/main/java/org/traccar/protocol/TekProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TelemaxProtocol.java b/src/main/java/org/traccar/protocol/TelemaxProtocol.java index 9e9cbb50e..792a5b176 100644 --- a/src/main/java/org/traccar/protocol/TelemaxProtocol.java +++ b/src/main/java/org/traccar/protocol/TelemaxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TelemaxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TelicProtocol.java b/src/main/java/org/traccar/protocol/TelicProtocol.java index 9ef7864ca..fc5bdf0d1 100644 --- a/src/main/java/org/traccar/protocol/TelicProtocol.java +++ b/src/main/java/org/traccar/protocol/TelicProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TelicProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java index 3a0962584..aabc24887 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java @@ -29,7 +29,7 @@ public class TeltonikaFrameDecoder extends BaseFrameDecoder { protected Object decode( ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - while (buf.isReadable() && buf.getByte(buf.readerIndex()) == (byte) 0xff) { + if (buf.isReadable() && buf.getByte(buf.readerIndex()) == (byte) 0xff) { return buf.readRetainedSlice(1); } diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocol.java b/src/main/java/org/traccar/protocol/TeltonikaProtocol.java index 38283cb64..f2d610251 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocol.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TeltonikaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 929eca8aa..6197c6c13 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2023 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,7 +20,7 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; -import org.traccar.model.Device; +import org.traccar.helper.BufferUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -33,6 +33,7 @@ import org.traccar.model.Network; import org.traccar.model.Position; import java.net.SocketAddress; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.HashMap; @@ -112,18 +113,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } } - private boolean isPrintable(ByteBuf buf, int length) { - boolean printable = true; - for (int i = 0; i < length; i++) { - byte b = buf.getByte(buf.readerIndex() + i); - if (b < 32 && b != '\r' && b != '\n') { - printable = false; - break; - } - } - return printable; - } - private void decodeSerial( Channel channel, SocketAddress remoteAddress, DeviceSession deviceSession, Position position, ByteBuf buf) { @@ -169,7 +158,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_TYPE, type); int length = buf.readInt(); - if (isPrintable(buf, length)) { + if (BufferUtil.isPrintable(buf, length)) { 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(";"); @@ -231,6 +220,8 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(26, null, (p, b) -> p.set("bleTemp2", b.readShort() * 0.01)); register(27, null, (p, b) -> p.set("bleTemp3", b.readShort() * 0.01)); register(28, null, (p, b) -> p.set("bleTemp4", b.readShort() * 0.01)); + register(30, fmbXXX, (p, b) -> p.set("faultCount", b.readUnsignedByte())); + register(32, fmbXXX, (p, b) -> p.set(Position.KEY_COOLANT_TEMP, b.readByte())); register(66, null, (p, b) -> p.set(Position.KEY_POWER, b.readUnsignedShort() * 0.001)); register(67, null, (p, b) -> p.set(Position.KEY_BATTERY, b.readUnsignedShort() * 0.001)); register(68, fmbXXX, (p, b) -> p.set("batteryCurrent", b.readUnsignedShort() * 0.001)); @@ -239,28 +230,52 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(74, fmbXXX, (p, b) -> p.set(Position.PREFIX_TEMP + 3, b.readInt() * 0.1)); register(75, fmbXXX, (p, b) -> p.set(Position.PREFIX_TEMP + 4, b.readInt() * 0.1)); register(78, null, (p, b) -> { - long driverUniqueId = b.readLong(); + long driverUniqueId = b.readLongLE(); if (driverUniqueId > 0) { p.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", driverUniqueId)); } }); register(80, fmbXXX, (p, b) -> p.set("dataMode", b.readUnsignedByte())); + register(81, fmbXXX, (p, b) -> p.set(Position.KEY_OBD_SPEED, b.readUnsignedByte())); + register(82, fmbXXX, (p, b) -> p.set(Position.KEY_THROTTLE, b.readUnsignedByte())); + register(83, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_USED, b.readUnsignedInt() * 0.1)); + register(84, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_LEVEL, b.readUnsignedShort() * 0.1)); + register(85, fmbXXX, (p, b) -> p.set(Position.KEY_RPM, b.readUnsignedShort())); + register(87, fmbXXX, (p, b) -> p.set(Position.KEY_OBD_ODOMETER, b.readUnsignedInt())); + register(89, fmbXXX, (p, b) -> p.set("fuelLevelPercentage", b.readUnsignedByte())); register(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort())); - register(115, fmbXXX, (p, b) -> p.set(Position.KEY_COOLANT_TEMP, b.readShort() * 0.1)); + register(110, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_CONSUMPTION, b.readUnsignedShort() * 0.1)); + register(113, fmbXXX, (p, b) -> p.set(Position.KEY_BATTERY_LEVEL, b.readUnsignedByte())); register(179, null, (p, b) -> p.set(Position.PREFIX_OUT + 1, b.readUnsignedByte() > 0)); register(180, null, (p, b) -> p.set(Position.PREFIX_OUT + 2, b.readUnsignedByte() > 0)); register(181, null, (p, b) -> p.set(Position.KEY_PDOP, b.readUnsignedShort() * 0.1)); register(182, null, (p, b) -> p.set(Position.KEY_HDOP, b.readUnsignedShort() * 0.1)); register(199, null, (p, b) -> p.set(Position.KEY_ODOMETER_TRIP, b.readUnsignedInt())); register(200, fmbXXX, (p, b) -> p.set("sleepMode", b.readUnsignedByte())); - register(205, fmbXXX, (p, b) -> p.set("cid", b.readUnsignedShort())); + register(205, fmbXXX, (p, b) -> p.set("cid2g", b.readUnsignedShort())); register(206, fmbXXX, (p, b) -> p.set("lac", b.readUnsignedShort())); + register(232, fmbXXX, (p, b) -> p.set("cngStatus", b.readUnsignedByte() > 0)); + register(233, fmbXXX, (p, b) -> p.set("cngUsed", b.readUnsignedInt() * 0.1)); + register(234, fmbXXX, (p, b) -> p.set("cngLevel", b.readUnsignedShort())); + register(235, fmbXXX, (p, b) -> p.set("oilLevel", b.readUnsignedByte())); register(236, null, (p, b) -> { p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_GENERAL : null); }); register(239, null, (p, b) -> p.set(Position.KEY_IGNITION, b.readUnsignedByte() > 0)); register(240, null, (p, b) -> p.set(Position.KEY_MOTION, b.readUnsignedByte() > 0)); register(241, null, (p, b) -> p.set(Position.KEY_OPERATOR, b.readUnsignedInt())); + register(246, fmbXXX, (p, b) -> { + p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_TOW : null); + }); + register(247, fmbXXX, (p, b) -> { + p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_ACCIDENT : null); + }); + register(249, fmbXXX, (p, b) -> { + p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_JAMMING : null); + }); + register(252, fmbXXX, (p, b) -> { + p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_POWER_CUT : null); + }); register(253, null, (p, b) -> { switch (b.readUnsignedByte()) { case 1: @@ -276,6 +291,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { break; } }); + register(636, fmbXXX, (p, b) -> p.set("cid4g", b.readUnsignedInt())); } private void decodeGh3000Parameter(Position position, int id, ByteBuf buf, int length) { @@ -366,14 +382,23 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { position.setNetwork(network); } } else { - Integer cid = (Integer) position.getAttributes().remove("cid"); + Integer cid2g = (Integer) position.getAttributes().remove("cid2g"); + Long cid4g = (Long) position.getAttributes().remove("cid4g"); Integer lac = (Integer) position.getAttributes().remove("lac"); - if (cid != null && lac != null) { - CellTower cellTower = CellTower.fromLacCid(getConfig(), lac, cid); + if (lac != null && (cid2g != null || cid4g != null)) { + Network network = new Network(); + CellTower cellTower; + if (cid2g != null) { + cellTower = CellTower.fromLacCid(getConfig(), lac, cid2g); + } else { + cellTower = CellTower.fromLacCid(getConfig(), lac, cid4g); + network.setRadioType("lte"); + } long operator = position.getInteger(Position.KEY_OPERATOR); if (operator >= 1000) { cellTower.setOperator(operator); } + network.addCellTower(cellTower); position.setNetwork(new Network(cellTower)); } } @@ -563,6 +588,38 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } index += 1; } + } else if (id == 548 || id == 10829 || id == 10831) { + ByteBuf data = buf.readSlice(length); + data.readUnsignedByte(); // header + for (int i = 1; data.isReadable(); i++) { + ByteBuf beacon = data.readSlice(data.readUnsignedByte()); + while (beacon.isReadable()) { + int parameterId = beacon.readUnsignedByte(); + int parameterLength = beacon.readUnsignedByte(); + switch (parameterId) { + case 0: + position.set("tag" + i + "Rssi", (int) beacon.readByte()); + break; + case 1: + String beaconId = ByteBufUtil.hexDump(beacon.readSlice(parameterLength)); + position.set("tag" + i + "Id", beaconId); + break; + case 2: + String beaconData = ByteBufUtil.hexDump(beacon.readSlice(parameterLength)); + position.set("tag" + i + "Data", beaconData); + break; + case 13: + position.set("tag" + i + "LowBattery", beacon.readUnsignedByte()); + break; + case 14: + position.set("tag" + i + "Battery", beacon.readUnsignedShort()); + break; + default: + beacon.skipBytes(parameterLength); + break; + } + } + } } else { position.set(Position.PREFIX_IO + id, ByteBufUtil.hexDump(buf.readSlice(length))); } @@ -571,6 +628,14 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { decodeNetwork(position, model); + if (model != null && model.matches("FM.6..")) { + Long driverMsb = (Long) position.getAttributes().get("io195"); + Long driverLsb = (Long) position.getAttributes().get("io196"); + if (driverMsb != null && driverLsb != null) { + String driver = new String(ByteBuffer.allocate(16).putLong(driverMsb).putLong(driverLsb).array()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, driver); + } + } } private List<Position> parseData( @@ -588,7 +653,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { if (deviceSession == null) { return null; } - String model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel(); for (int i = 0; i < count; i++) { Position position = new Position(getProtocolName()); @@ -600,9 +664,13 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedByte(); // type int length = buf.readInt() - 4; getLastLocation(position, new Date(buf.readUnsignedInt() * 1000)); - if (isPrintable(buf, length)) { - position.set(Position.KEY_RESULT, - buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim()); + if (BufferUtil.isPrintable(buf, length)) { + String data = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim(); + if (data.startsWith("GTSL")) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, data.split("\\|")[4]); + } else { + position.set(Position.KEY_RESULT, data); + } } else { position.set(Position.KEY_RESULT, ByteBufUtil.hexDump(buf.readSlice(length))); @@ -610,7 +678,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } else if (codec == CODEC_12) { decodeSerial(channel, remoteAddress, deviceSession, position, buf); } else { - decodeLocation(position, buf, codec, model); + decodeLocation(position, buf, codec, getDeviceModel(deviceSession)); } if (!position.getOutdated() || !position.getAttributes().isEmpty()) { diff --git a/src/main/java/org/traccar/protocol/TeraTrackProtocol.java b/src/main/java/org/traccar/protocol/TeraTrackProtocol.java index 73219cc5e..e872ddf42 100644 --- a/src/main/java/org/traccar/protocol/TeraTrackProtocol.java +++ b/src/main/java/org/traccar/protocol/TeraTrackProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TeraTrackProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java index 313210f63..be4b98e4c 100644 --- a/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java @@ -23,8 +23,8 @@ import org.traccar.Protocol; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; -import javax.json.Json; -import javax.json.JsonObject; +import jakarta.json.Json; +import jakarta.json.JsonObject; import java.io.StringReader; import java.net.SocketAddress; import java.text.DateFormat; @@ -63,7 +63,7 @@ public class TeraTrackProtocolDecoder extends BaseProtocolDecoder { position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(json.getString("Speed")))); position.set(Position.KEY_ODOMETER, Integer.parseInt(json.getString("Mileage"))); - position.set(Position.KEY_BLOCKED, json.getString("LockOpen").equals("0")); + position.set(Position.KEY_LOCK, json.getString("LockOpen").equals("0")); position.set(Position.KEY_DRIVER_UNIQUE_ID, json.getString("CardNo")); position.set(Position.KEY_ALARM, json.getString("LowPower").equals("1") ? Position.ALARM_LOW_POWER : null); position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(json.getString("Power"))); diff --git a/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java b/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java index 38bf078aa..b23dadf08 100644 --- a/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java +++ b/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ThinkPowerProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java b/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java index 782b0a352..34b80ba87 100644 --- a/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java +++ b/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ThinkRaceProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ThurayaProtocol.java b/src/main/java/org/traccar/protocol/ThurayaProtocol.java index f709a1183..33d486f6b 100644 --- a/src/main/java/org/traccar/protocol/ThurayaProtocol.java +++ b/src/main/java/org/traccar/protocol/ThurayaProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class ThurayaProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Tk102Protocol.java b/src/main/java/org/traccar/protocol/Tk102Protocol.java index 150e83ab3..b6a82981b 100644 --- a/src/main/java/org/traccar/protocol/Tk102Protocol.java +++ b/src/main/java/org/traccar/protocol/Tk102Protocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Tk102Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Tk103Protocol.java b/src/main/java/org/traccar/protocol/Tk103Protocol.java index cf09886f5..b641ef083 100644 --- a/src/main/java/org/traccar/protocol/Tk103Protocol.java +++ b/src/main/java/org/traccar/protocol/Tk103Protocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Tk103Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java index b343c3b33..6c926da90 100644 --- a/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2023 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. @@ -15,8 +15,11 @@ */ 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.helper.DataConverter; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -448,6 +451,106 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder { return position; } + private Position decodeBms(Channel channel, SocketAddress remoteAddress, String sentence) { + String id = sentence.substring(1, 13); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + String payload = sentence.substring(1 + 12 + 4, sentence.length() - 1); + + if (sentence.startsWith("BS50", 1 + 12)) { + + ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(payload)); + + buf.readUnsignedByte(); + buf.readUnsignedByte(); + buf.readUnsignedByte(); // header + + int batteryCount = buf.readUnsignedByte(); + for (int i = 1; i <= 24; i++) { + int voltage = buf.readUnsignedShortLE(); + if (i <= batteryCount) { + position.set("battery" + i, voltage * 0.001); + } + } + + position.set(Position.KEY_CHARGE, buf.readUnsignedByte() == 0); + position.set("current", buf.readUnsignedShortLE() * 0.1); + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + position.set("batteryOverheat", buf.readUnsignedByte() > 0); + position.set("chargeProtection", buf.readUnsignedByte() > 0); + position.set("dischargeProtection", buf.readUnsignedByte() > 0); + buf.readUnsignedByte(); // drop line + buf.readUnsignedByte(); // balanced + position.set("cycles", buf.readUnsignedShortLE()); + position.set("faultAlarm", buf.readUnsignedByte()); + + buf.skipBytes(6); + + int temperatureCount = buf.readUnsignedByte(); + position.set("powerTemp", buf.readUnsignedByte() - 40); + position.set("equilibriumTemp", buf.readUnsignedByte() - 40); + for (int i = 1; i <= 7; i++) { + int temperature = buf.readUnsignedByte() - 40; + if (i <= temperatureCount) { + position.set("batteryTemp" + i, temperature); + } + } + + position.set("calibrationCapacity", buf.readUnsignedShortLE() * 0.01); + position.set("dischargeCapacity", buf.readUnsignedIntLE()); + + } else { + + String[] values = payload.split(","); + for (String value : values) { + String[] pair = value.split(":"); + int key = Integer.parseInt(pair[0], 16); + ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(pair[1])); + switch (key) { + case 0x90: + position.set("cumulativeVoltage", buf.readUnsignedShortLE() * 0.1); + position.set("gatherVoltage", buf.readUnsignedShortLE() * 0.1); + position.set("current", (buf.readUnsignedShortLE() - 30000) * 0.1); + position.set("soc", buf.readUnsignedShortLE() * 0.1); + break; + case 0x91: + position.set("maxCellVoltage", buf.readUnsignedShortLE() * 0.001); + position.set("maxCellVoltageCount", buf.readUnsignedByte()); + position.set("minCellVoltage", buf.readUnsignedShortLE() * 0.001); + position.set("minCellVoltageCount", buf.readUnsignedByte()); + break; + case 0x92: + position.set("maxTemp", buf.readUnsignedByte() - 40); + position.set("maxTempCount", buf.readUnsignedByte()); + position.set("minTemp", buf.readUnsignedByte() - 40); + position.set("minTempCount", buf.readUnsignedByte()); + break; + case 0x96: + buf.readUnsignedByte(); // frame + while (buf.isReadable()) { + position.set("cellTemp" + buf.readerIndex(), buf.readUnsignedByte() - 40); + } + break; + default: + break; + } + + } + + } + + return position; + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -477,6 +580,8 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder { return decodeLbsWifi(channel, remoteAddress, sentence); } else if (sentence.contains("BV00")) { return decodeVin(channel, remoteAddress, sentence); + } else if (sentence.contains("BS50") || sentence.contains("BS51")) { + return decodeBms(channel, remoteAddress, sentence); } Parser parser = new Parser(PATTERN, sentence); diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocol.java b/src/main/java/org/traccar/protocol/Tlt2hProtocol.java index b10271f7d..6763e9b6b 100644 --- a/src/main/java/org/traccar/protocol/Tlt2hProtocol.java +++ b/src/main/java/org/traccar/protocol/Tlt2hProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Tlt2hProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java index e85bdf9b3..6be3d2dc3 100644 --- a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2024 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. @@ -55,16 +55,20 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_POSITION = new PatternBuilder() .text("#") - .number("(?:(dd)|x*)") // cell or voltage + .number("(?:(dd|dddd)|x*)") // cell or voltage .groupBegin() - .number("#(d+),") // mcc + .text("#") + .groupBegin() + .number("(d+),") // mcc .number("(d+),") // mnc .number("(x+),") // lac .number("(x+)") // cell id .groupEnd("?") + .groupEnd("?") .text("$GPRMC,") - .number("(dd)(dd)(dd).d+,") // time (hhmmss.sss) + .number("(?:(dd)(dd)(dd).d+)?,") // time (hhmmss.sss) .expression("([AVL]),") // validity + .groupBegin() .number("(d+)(dd.d+),") // latitude .expression("([NS]),") .number("(d+)(dd.d+),") // longitude @@ -72,14 +76,16 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { .number("(d+.?d*)?,") // speed .number("(d+.?d*)?,") // course .number("(dd)(dd)(dd)") // date (ddmmyy) + .groupEnd("?") .any() .compile(); private static final Pattern PATTERN_WIFI = new PatternBuilder() .text("#") - .number("(?:(dd)|x+)") // cell or voltage + .number("(?:(dd|dddd)|x+)") // cell or voltage + .expression("#?") .groupBegin() - .number("#(d+),") // mcc + .number("(d+),") // mcc .number("(d+),") // mnc .number("(x+),") // lac .number("(x+)") // cell id @@ -178,7 +184,8 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { if (parser.matches()) { if (parser.hasNext()) { - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.1); + int voltage = parser.nextInt(); + position.set(Position.KEY_BATTERY, voltage > 100 ? voltage * 0.001 : voltage * 0.1); } if (parser.hasNext(4)) { @@ -188,17 +195,26 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { position.setNetwork(network); } - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + DateBuilder dateBuilder = new DateBuilder(); + if (parser.hasNext(3)) { + 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(0)); - position.setCourse(parser.nextDouble(0)); - dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setTime(dateBuilder.getDate()); + if (parser.hasNext()) { + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + } else { + getLastLocation(position, null); + } } else { continue; @@ -209,7 +225,10 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { parser = new Parser(PATTERN_WIFI, message); if (parser.matches()) { - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.1); + if (parser.hasNext()) { + int voltage = parser.nextInt(); + position.set(Position.KEY_BATTERY, voltage > 100 ? voltage * 0.001 : voltage * 0.1); + } Network network = new Network(); if (parser.hasNext(4)) { @@ -230,6 +249,8 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); getLastLocation(position, dateBuilder.getDate()); + } else { + continue; } } else { diff --git a/src/main/java/org/traccar/protocol/TlvProtocol.java b/src/main/java/org/traccar/protocol/TlvProtocol.java index 9d83388c9..f99676d23 100644 --- a/src/main/java/org/traccar/protocol/TlvProtocol.java +++ b/src/main/java/org/traccar/protocol/TlvProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TlvProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TmgProtocol.java b/src/main/java/org/traccar/protocol/TmgProtocol.java index e078c425b..dbba648be 100644 --- a/src/main/java/org/traccar/protocol/TmgProtocol.java +++ b/src/main/java/org/traccar/protocol/TmgProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TmgProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TopflytechProtocol.java b/src/main/java/org/traccar/protocol/TopflytechProtocol.java index 339d2fc8d..a658235ab 100644 --- a/src/main/java/org/traccar/protocol/TopflytechProtocol.java +++ b/src/main/java/org/traccar/protocol/TopflytechProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TopflytechProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TopinProtocol.java b/src/main/java/org/traccar/protocol/TopinProtocol.java index b15373d71..1a558f617 100644 --- a/src/main/java/org/traccar/protocol/TopinProtocol.java +++ b/src/main/java/org/traccar/protocol/TopinProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2023 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 @@ import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; +import org.traccar.config.Keys; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TopinProtocol extends BaseProtocol { @Inject public TopinProtocol(Config config) { - setSupportedDataCommands( - Command.TYPE_SOS_NUMBER); + if (!config.getBoolean(Keys.PROTOCOL_DISABLE_COMMANDS.withPrefix(getName()))) { + setSupportedDataCommands( + Command.TYPE_SOS_NUMBER); + } addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { diff --git a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java index a1d5481db..c7b816818 100644 --- a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java @@ -48,7 +48,12 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_GPS = 0x10; public static final int MSG_GPS_OFFLINE = 0x11; public static final int MSG_STATUS = 0x13; + public static final int MSG_SLEEP = 0x14; + public static final int MSG_FACTORY_RESET = 0x15; public static final int MSG_WIFI_OFFLINE = 0x17; + public static final int MSG_LBS_WIFI = 0x18; + public static final int MSG_LBS_WIFI_OFFLINE = 0x19; + public static final int MSG_LBS_WIFI_2 = 0x1A; public static final int MSG_TIME_UPDATE = 0x30; public static final int MSG_SOS_NUMBER = 0x41; public static final int MSG_WIFI = 0x69; @@ -216,7 +221,8 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { return position; - } else if (type == MSG_WIFI || type == MSG_WIFI_OFFLINE) { + } else if (type == MSG_WIFI || type == MSG_WIFI_OFFLINE + || type == MSG_LBS_WIFI || type == MSG_LBS_WIFI_2 || type == MSG_LBS_WIFI_OFFLINE) { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); diff --git a/src/main/java/org/traccar/protocol/TotemProtocol.java b/src/main/java/org/traccar/protocol/TotemProtocol.java index 9ab36fd0b..b02d4f1fc 100644 --- a/src/main/java/org/traccar/protocol/TotemProtocol.java +++ b/src/main/java/org/traccar/protocol/TotemProtocol.java @@ -23,7 +23,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TotemProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java b/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java index 9d0d794f8..6f039c324 100644 --- a/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2023 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. @@ -135,7 +135,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN4 = new PatternBuilder() .text("$$") // header .number("dddd") // length - .number("(xx)") // type + .number("xx") // type .number("(d+)|") // imei .number("(x{8})") // status .number("(dd)(dd)(dd)") // date (yymmdd) @@ -176,7 +176,21 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { .any() .compile(); - private static final Pattern PATTERN_OBD = new PatternBuilder() + private static final Pattern PATTERN_E2 = new PatternBuilder() + .text("$$") // header + .number("dddd") // length + .number("xx") // type + .number("(d+)|") // imei + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .expression("(.+)") // rfid + .number("|xx") // checksum + .any() + .compile(); + + private static final Pattern PATTERN_E5 = new PatternBuilder() .text("$$") // header .number("dddd") // length .number("xx") // type @@ -257,7 +271,20 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { } } - private boolean decode12(Position position, Parser parser, Pattern pattern) { + private Position decode12(Channel channel, SocketAddress remoteAddress, String sentence, Pattern pattern) { + + Parser parser = new Parser(pattern, 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()); if (parser.hasNext()) { position.set(Position.KEY_ALARM, decodeAlarm123(Short.parseShort(parser.next(), 16))); @@ -283,7 +310,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { year = parser.nextInt(0); } if (year == 0) { - return false; // ignore invalid data + return null; // ignore invalid data } dateBuilder.setDate(year, month, day); position.setTime(dateBuilder.getDate()); @@ -331,10 +358,23 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_TEMP + 1, parser.next()); position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000); - return true; + return position; } - private boolean decode3(Position position, Parser parser) { + private Position decode3(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN3, 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()); if (parser.hasNext()) { position.set(Position.KEY_ALARM, decodeAlarm123(Short.parseShort(parser.next(), 16))); @@ -363,10 +403,36 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { position.setLatitude(parser.nextCoordinate()); position.setLongitude(parser.nextCoordinate()); - return true; + return position; } - private boolean decode4(Position position, Parser parser) { + private Position decode4(Channel channel, SocketAddress remoteAddress, String sentence) { + + int type = Integer.parseInt(sentence.substring(6, 8), 16); + + switch (type) { + case 0xE2: + return decodeE2(channel, remoteAddress, sentence); + case 0xE5: + return decodeE5(channel, remoteAddress, sentence); + default: + break; + } + + Parser parser = new Parser(PATTERN4, 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()); + + position.set(Position.KEY_ALARM, decodeAlarm4(type)); long status = parser.nextHexLong(); @@ -427,10 +493,48 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { position.setLatitude(parser.nextCoordinate()); position.setLongitude(parser.nextCoordinate()); - return true; + return position; } - private boolean decodeObd(Position position, Parser parser) { + private Position decodeE2(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_E2, 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()); + + position.setValid(true); + position.setTime(parser.nextDateTime()); + position.setLongitude(parser.nextDouble()); + position.setLatitude(parser.nextDouble()); + + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + + return position; + } + + private Position decodeE5(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_E5, 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()); position.setValid(true); position.setTime(parser.nextDateTime()); @@ -451,7 +555,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_THROTTLE, parser.nextInt()); position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); - return true; + return position; } @Override @@ -459,50 +563,23 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { String sentence = (String) msg; - Pattern pattern = PATTERN3; - if (sentence.contains("$Cloud")) { - pattern = PATTERN_OBD; - } else if (sentence.charAt(2) == '0') { - pattern = PATTERN4; + + Position position; + if (sentence.charAt(2) == '0') { + position = decode4(channel, remoteAddress, sentence); } else if (sentence.contains("$GPRMC")) { - pattern = PATTERN1; + position = decode12(channel, remoteAddress, sentence, PATTERN1); } else { int index = sentence.indexOf('|'); if (index != -1 && sentence.indexOf('|', index + 1) != -1) { - pattern = PATTERN2; + position = decode12(channel, remoteAddress, sentence, PATTERN2); + } else { + position = decode3(channel, remoteAddress, sentence); } } - Parser parser = new Parser(pattern, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - if (pattern == PATTERN4) { - position.set(Position.KEY_ALARM, decodeAlarm4(parser.nextHexInt())); - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - boolean result; - if (pattern == PATTERN1 || pattern == PATTERN2) { - result = decode12(position, parser, pattern); - } else if (pattern == PATTERN3) { - result = decode3(position, parser); - } else if (pattern == PATTERN4) { - result = decode4(position, parser); - } else { - result = decodeObd(position, parser); - } - if (channel != null) { - if (pattern == PATTERN4) { + if (sentence.charAt(2) == '0') { String response = "$$0014AA" + sentence.substring(sentence.length() - 6, sentence.length() - 2); response += String.format("%02X", Checksum.xor(response)).toUpperCase(); channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); @@ -511,7 +588,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder { } } - return result ? position : null; + return position; } } diff --git a/src/main/java/org/traccar/protocol/Tr20Protocol.java b/src/main/java/org/traccar/protocol/Tr20Protocol.java index 615fdab28..3b3fc02b6 100644 --- a/src/main/java/org/traccar/protocol/Tr20Protocol.java +++ b/src/main/java/org/traccar/protocol/Tr20Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Tr20Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Tr900Protocol.java b/src/main/java/org/traccar/protocol/Tr900Protocol.java index 162cbe651..c5f357604 100644 --- a/src/main/java/org/traccar/protocol/Tr900Protocol.java +++ b/src/main/java/org/traccar/protocol/Tr900Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Tr900Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TrackboxProtocol.java b/src/main/java/org/traccar/protocol/TrackboxProtocol.java index 4236144a3..eadcd07f9 100644 --- a/src/main/java/org/traccar/protocol/TrackboxProtocol.java +++ b/src/main/java/org/traccar/protocol/TrackboxProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TrackboxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TrakMateProtocol.java b/src/main/java/org/traccar/protocol/TrakMateProtocol.java index b7637e6f3..f4e7c5e60 100644 --- a/src/main/java/org/traccar/protocol/TrakMateProtocol.java +++ b/src/main/java/org/traccar/protocol/TrakMateProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TrakMateProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java b/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java index e4c94dc77..72cadf21a 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 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2023 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,9 +29,13 @@ public class TramigoFrameDecoder extends BaseFrameDecoder { return null; } + int protocol = buf.getUnsignedByte(buf.readerIndex()); + int length; - if (buf.getUnsignedByte(buf.readerIndex()) == 0x80) { + if (protocol == 0x80) { length = buf.getUnsignedShortLE(buf.readerIndex() + 6); + } else if (protocol == 0x02 || protocol == 0x04) { + length = buf.getUnsignedShortLE(buf.readerIndex() + 1); } else { length = buf.getUnsignedShort(buf.readerIndex() + 6); } diff --git a/src/main/java/org/traccar/protocol/TramigoProtocol.java b/src/main/java/org/traccar/protocol/TramigoProtocol.java index 79a59abd3..5d8baf2a9 100644 --- a/src/main/java/org/traccar/protocol/TramigoProtocol.java +++ b/src/main/java/org/traccar/protocol/TramigoProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TramigoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java index 21dd78da3..4a9a9a58f 100644 --- a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2014 - 2023 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,8 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Checksum; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -29,6 +31,7 @@ import org.traccar.model.Position; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.text.DateFormat; +import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; @@ -42,9 +45,6 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { super(protocol); } - public static final int MSG_COMPACT = 0x0100; - public static final int MSG_FULL = 0x00FE; - private static final String[] DIRECTIONS = new String[] {"N", "NE", "E", "SE", "S", "SW", "W", "NW"}; @Override @@ -54,34 +54,47 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { ByteBuf buf = (ByteBuf) msg; int protocol = buf.readUnsignedByte(); - boolean legacy = protocol == 0x80; + + if (protocol == 0x01) { + return decode01(channel, remoteAddress, buf); + } else if (protocol == 0x04) { + return decode04(channel, remoteAddress, buf); + } else if (protocol == 0x80) { + return decode80(channel, remoteAddress, buf); + } + + return null; + } + + private Position decode01(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { buf.readUnsignedByte(); // version id - int index = legacy ? buf.readUnsignedShort() : buf.readUnsignedShortLE(); - int type = legacy ? buf.readUnsignedShort() : buf.readUnsignedShortLE(); - buf.readUnsignedShort(); // length - buf.readUnsignedShort(); // mask - buf.readUnsignedShort(); // checksum - long id = legacy ? buf.readUnsignedInt() : buf.readUnsignedIntLE(); - buf.readUnsignedInt(); // time + int index = buf.readUnsignedShortLE(); + int type = buf.readUnsignedShortLE(); - Position position = new Position(getProtocolName()); - position.set(Position.KEY_INDEX, index); - position.setValid(true); + if (type == 0x0100 || type == 0x00FE) { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); + buf.readUnsignedShort(); // length + buf.readUnsignedShort(); // mask + buf.readUnsignedShort(); // checksum + long id = buf.readUnsignedIntLE(); + buf.readUnsignedInt(); // time - if (protocol == 0x01 && (type == MSG_COMPACT || type == MSG_FULL)) { + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.set(Position.KEY_INDEX, index); // need to send ack? buf.readUnsignedShortLE(); // report trigger buf.readUnsignedShortLE(); // state flag + position.setValid(true); position.setLatitude(buf.readUnsignedIntLE() * 0.0000001); position.setLongitude(buf.readUnsignedIntLE() * 0.0000001); @@ -105,56 +118,183 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder { return position; - } else if (legacy) { + } - if (channel != null) { - channel.writeAndFlush(new NetworkMessage( - Unpooled.copiedBuffer("gprs,ack," + index, StandardCharsets.US_ASCII), remoteAddress)); - } + return null; - String sentence = buf.toString(StandardCharsets.US_ASCII); + } - Pattern pattern = Pattern.compile("(-?\\d+\\.\\d+), (-?\\d+\\.\\d+)"); - Matcher matcher = pattern.matcher(sentence); - if (!matcher.find()) { - return null; - } - position.setLatitude(Double.parseDouble(matcher.group(1))); - position.setLongitude(Double.parseDouble(matcher.group(2))); - - pattern = Pattern.compile("([NSWE]{1,2}) with speed (\\d+) km/h"); - matcher = pattern.matcher(sentence); - if (matcher.find()) { - for (int i = 0; i < DIRECTIONS.length; i++) { - if (matcher.group(1).equals(DIRECTIONS[i])) { - position.setCourse(i * 45.0); - break; - } - } - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(matcher.group(2)))); - } + private Position decode04(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - pattern = Pattern.compile("(\\d{1,2}:\\d{2}(:\\d{2})? \\w{3} \\d{1,2})"); - matcher = pattern.matcher(sentence); - if (!matcher.find()) { - return null; - } - DateFormat dateFormat = new SimpleDateFormat( - matcher.group(2) != null ? "HH:mm:ss MMM d yyyy" : "HH:mm MMM d yyyy", Locale.ENGLISH); - position.setTime(DateUtil.correctYear( - dateFormat.parse(matcher.group(1) + " " + Calendar.getInstance().get(Calendar.YEAR)))); - - if (sentence.contains("Ignition on detected")) { - position.set(Position.KEY_IGNITION, true); - } else if (sentence.contains("Ignition off detected")) { - position.set(Position.KEY_IGNITION, false); + buf.readUnsignedShortLE(); // length + buf.readUnsignedShortLE(); // checksum + int index = buf.readUnsignedShortLE(); + long id1 = buf.readUnsignedIntLE(); + long id2 = buf.readUnsignedIntLE(); + long time = buf.readUnsignedIntLE(); + + String id = String.format("%08d%07d", id1, id2); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(0x04); // protocol + response.writeShortLE(24); // length + response.writeShortLE(0); // checksum + response.writeShortLE(index); + response.writeIntLE((int) id1); + response.writeIntLE((int) id2); + response.writeIntLE((int) time); + + response.writeByte(0xff); // acknowledgement + response.writeShortLE(index); + response.writeShortLE(0); // success + + response.setShortLE(3, Checksum.crc16(Checksum.CRC16_CCITT_FALSE, response.nioBuffer())); + + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.set(Position.KEY_INDEX, index); + + position.setDeviceTime(new Date(time * 1000)); + + while (buf.isReadable()) { + int type = buf.readUnsignedByte(); + switch (type) { + case 0: + position.set(Position.KEY_EVENT, buf.readUnsignedShortLE()); + buf.readUnsignedIntLE(); // event data + + int status = buf.readUnsignedShortLE(); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 5)); + position.set(Position.KEY_STATUS, status); + + position.setValid(true); + position.setLatitude(buf.readIntLE() * 0.00001); + position.setLongitude(buf.readIntLE() * 0.00001); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); + position.setCourse(buf.readUnsignedShortLE()); + + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set(Position.KEY_GPS, buf.readUnsignedByte()); + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedShortLE()); + position.set("maxAcceleration", buf.readUnsignedShortLE() * 0.001); + position.set("maxDeceleration", buf.readUnsignedShortLE() * 0.001); + buf.readUnsignedShortLE(); // bearing to landmark + buf.readUnsignedIntLE(); // distance to landmark + + position.setFixTime(new Date(buf.readUnsignedIntLE() * 1000)); + + buf.readUnsignedByte(); // reserved + break; + case 1: + buf.skipBytes(buf.readUnsignedShortLE() - 3); // landmark + break; + case 4: + buf.skipBytes(53); // trip + break; + case 20: + buf.skipBytes(32); // extended + break; + case 22: + buf.readUnsignedByte(); // zone flag + buf.skipBytes(buf.readUnsignedShortLE()); // zone name + break; + case 30: + buf.skipBytes(79); // system status + break; + case 40: + buf.skipBytes(40); // analog + break; + case 50: + buf.skipBytes(buf.readUnsignedShortLE() - 3); // console + break; + case 255: + buf.skipBytes(4); // acknowledgement + break; + default: + throw new IllegalArgumentException(String.format("Unknown type %d", type)); } + } - return position; + return position.getValid() ? position : null; + + } + private Position decode80(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws ParseException { + + buf.readUnsignedByte(); // version id + int index = buf.readUnsignedShort(); + buf.readUnsignedShort(); // type + + buf.readUnsignedShort(); // length + buf.readUnsignedShort(); // mask + buf.readUnsignedShort(); // checksum + long id = buf.readUnsignedInt(); + buf.readUnsignedInt(); // time + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); + if (deviceSession == null) { + return null; } - return null; + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.set(Position.KEY_INDEX, index); + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage( + Unpooled.copiedBuffer("gprs,ack," + index, StandardCharsets.US_ASCII), remoteAddress)); + } + + String sentence = buf.toString(StandardCharsets.US_ASCII); + + Pattern pattern = Pattern.compile("(-?\\d+\\.\\d+), (-?\\d+\\.\\d+)"); + Matcher matcher = pattern.matcher(sentence); + if (!matcher.find()) { + return null; + } + position.setLatitude(Double.parseDouble(matcher.group(1))); + position.setLongitude(Double.parseDouble(matcher.group(2))); + position.setValid(true); + + pattern = Pattern.compile("([NSWE]{1,2}) with speed (\\d+) km/h"); + matcher = pattern.matcher(sentence); + if (matcher.find()) { + for (int i = 0; i < DIRECTIONS.length; i++) { + if (matcher.group(1).equals(DIRECTIONS[i])) { + position.setCourse(i * 45.0); + break; + } + } + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(matcher.group(2)))); + } + + pattern = Pattern.compile("(\\d{1,2}:\\d{2}(:\\d{2})? \\w{3} \\d{1,2})"); + matcher = pattern.matcher(sentence); + if (!matcher.find()) { + return null; + } + DateFormat dateFormat = new SimpleDateFormat( + matcher.group(2) != null ? "HH:mm:ss MMM d yyyy" : "HH:mm MMM d yyyy", Locale.ENGLISH); + position.setTime(DateUtil.correctYear( + dateFormat.parse(matcher.group(1) + " " + Calendar.getInstance().get(Calendar.YEAR)))); + + if (sentence.contains("Ignition on detected")) { + position.set(Position.KEY_IGNITION, true); + } else if (sentence.contains("Ignition off detected")) { + position.set(Position.KEY_IGNITION, false); + } + + return position; + } } diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocol.java b/src/main/java/org/traccar/protocol/TranSyncProtocol.java new file mode 100644 index 000000000..fb37a1ab4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TranSyncProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023 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.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +import jakarta.inject.Inject; + +public class TranSyncProtocol extends BaseProtocol { + + @Inject + public TranSyncProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 1, 2, 0)); + pipeline.addLast(new TranSyncProtocolDecoder(TranSyncProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java new file mode 100644 index 000000000..816b5d2cf --- /dev/null +++ b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java @@ -0,0 +1,166 @@ +/* + * Copyright 2023 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.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.net.SocketAddress; + +public class TranSyncProtocolDecoder extends BaseProtocolDecoder { + + public TranSyncProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private String decodeAlarm(int value) { + switch (value) { + case 4: + return Position.ALARM_LOW_BATTERY; + case 6: + return Position.ALARM_POWER_RESTORED; + case 10: + return Position.ALARM_SOS; + case 13: + return Position.ALARM_BRAKING; + case 14: + return Position.ALARM_ACCELERATION; + case 17: + return Position.ALARM_OVERSPEED; + case 23: + return Position.ALARM_ACCIDENT; + default: + return null; + } + } + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedShort(); // header + buf.readByte(); // length + + int lac = buf.readUnsignedShort(); + + String deviceId = ByteBufUtil.hexDump(buf.readSlice(8)); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, deviceId); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedShort(); // index + buf.readUnsignedByte(); // type + + position.setTime(new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .getDate()); + + double latitude = buf.readUnsignedInt() / 1800000.0; + double longitude = buf.readUnsignedInt() / 1800000.0; + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setCourse(buf.readUnsignedShort()); + + int mnc = buf.readUnsignedByte(); + int cid = buf.readUnsignedShort(); + int status0 = buf.readUnsignedByte(); + + position.setValid(BitUtil.check(status0, 0)); + position.setLatitude(BitUtil.check(status0, 1) ? latitude : -latitude); + position.setLongitude(BitUtil.check(status0, 2) ? longitude : -longitude); + + position.set(Position.PREFIX_OUT + 1, BitUtil.check(status0, 7)); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(status0, 6)); + position.set(Position.PREFIX_IN + 3, BitUtil.check(status0, 5)); + if (BitUtil.check(status0, 4)) { + position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); + } + position.set(Position.KEY_IGNITION, BitUtil.check(status0, 3)); + + buf.readUnsignedByte(); // reserved + + int event = buf.readUnsignedByte(); + position.set(Position.KEY_ALARM, decodeAlarm(event)); + position.set(Position.KEY_EVENT, event); + + int status3 = buf.readUnsignedByte(); + if (BitUtil.check(status3, 7)) { + position.set(Position.KEY_ARCHIVE, true); + } + if (BitUtil.check(status3, 5)) { + position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); + } + + int rssi = buf.readUnsignedByte(); + CellTower cellTower = CellTower.fromLacCid(getConfig(), lac, cid); + cellTower.setMobileNetworkCode(mnc); + cellTower.setSignalStrength(rssi); + position.setNetwork(new Network(cellTower)); + + position.set(Position.KEY_BATTERY, (double) (buf.readUnsignedByte() / 10)); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_HDOP, buf.readUnsignedByte()); + position.set(Position.PREFIX_ADC + 1, (short) buf.readUnsignedShort()); + + if (buf.readableBytes() > 5) { + buf.readUnsignedByte(); // odometer id + int length = buf.readUnsignedByte(); + if (length > 0) { + position.set(Position.KEY_ODOMETER, buf.readBytes(length).readInt()); + } + } + if (buf.readableBytes() > 5) { + buf.readUnsignedByte(); // rfid id + int length = buf.readUnsignedByte(); + if (length > 0) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, ByteBufUtil.hexDump(buf.readSlice(length))); + } + } + if (buf.readableBytes() > 5) { + buf.readUnsignedByte(); // adc2 id + int length = buf.readUnsignedByte(); + if (length > 0) { + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); + } + } + if (buf.readableBytes() > 5) { + buf.readUnsignedByte(); // adc3 id + int length = buf.readUnsignedByte(); + if (length > 0 && length <= buf.readableBytes() - 2) { + position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort()); + } + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/TrvProtocol.java b/src/main/java/org/traccar/protocol/TrvProtocol.java index e67afbda2..7bdf3d2d0 100644 --- a/src/main/java/org/traccar/protocol/TrvProtocol.java +++ b/src/main/java/org/traccar/protocol/TrvProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TrvProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java index 9df29ae1b..02744f8ab 100644 --- a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java @@ -64,10 +64,20 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { .number("(d+),") // mnc .number("(d+),") // lac .number("(d+)") // cell + .groupBegin() + .text(",") + .expression("(") + .groupBegin() + .expression("[^\\|]+") // name + .number("|xx-xx-xx-xx-xx-xx") // mac + .number("|d+&?") // signal + .groupEnd("+") + .expression(")") + .groupEnd("?") .any() .compile(); - private static final Pattern PATTERN_HEATRBEAT = new PatternBuilder() + private static final Pattern PATTERN_HEARTBEAT = new PatternBuilder() .expression("[A-Z]{2,3}") .text("CP01,") .number("(ddd)") // gsm @@ -130,6 +140,16 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { } } + private void decodeWifi(Network network, String data) { + for (String wifi : data.split("&")) { + if (!wifi.isEmpty()) { + String[] values = wifi.split("\\|"); + network.addWifiAccessPoint(WifiAccessPoint.from( + values[1].replace('-', ':'), Integer.parseInt(values[2]))); + } + } + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -163,7 +183,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { if (type.equals("CP01")) { - Parser parser = new Parser(PATTERN_HEATRBEAT, sentence); + Parser parser = new Parser(PATTERN_HEARTBEAT, sentence); if (!parser.matches()) { return null; } @@ -208,8 +228,16 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { decodeCommon(position, parser); - position.setNetwork(new Network(CellTower.from( - parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt()))); + Network network = new Network(); + + network.addCellTower(CellTower.from( + parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt())); + + if (parser.hasNext()) { + decodeWifi(network, parser.next()); + } + + position.setNetwork(network); return position; @@ -241,12 +269,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { } } - for (String wifi : parser.next().split("&")) { - if (!wifi.isEmpty()) { - String[] values = wifi.split("\\|"); - network.addWifiAccessPoint(WifiAccessPoint.from(values[1], Integer.parseInt(values[2]))); - } - } + decodeWifi(network, parser.next()); position.setNetwork(network); diff --git a/src/main/java/org/traccar/protocol/Tt8850Protocol.java b/src/main/java/org/traccar/protocol/Tt8850Protocol.java index ab109e274..8e2800d90 100644 --- a/src/main/java/org/traccar/protocol/Tt8850Protocol.java +++ b/src/main/java/org/traccar/protocol/Tt8850Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Tt8850Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TytanProtocol.java b/src/main/java/org/traccar/protocol/TytanProtocol.java index cc3bc9b52..4fd3c807f 100644 --- a/src/main/java/org/traccar/protocol/TytanProtocol.java +++ b/src/main/java/org/traccar/protocol/TytanProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TytanProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TzoneProtocol.java b/src/main/java/org/traccar/protocol/TzoneProtocol.java index d25757b63..2df721049 100644 --- a/src/main/java/org/traccar/protocol/TzoneProtocol.java +++ b/src/main/java/org/traccar/protocol/TzoneProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class TzoneProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java index 8e84a6781..f0b1e709d 100644 --- a/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java @@ -204,30 +204,39 @@ public class TzoneProtocolDecoder extends BaseProtocolDecoder { } - private void decodeTags(Position position, ByteBuf buf) { + private void decodeTags(Position position, ByteBuf buf, int hardware) { int blockLength = buf.readUnsignedShort(); int blockEnd = buf.readerIndex() + blockLength; if (blockLength > 0) { - buf.readUnsignedByte(); // tag type + int type = buf.readUnsignedByte(); - int count = buf.readUnsignedByte(); - int tagLength = buf.readUnsignedByte(); + if (hardware != 0x153 || type >= 2) { - for (int i = 1; i <= count; i++) { - int tagEnd = buf.readerIndex() + tagLength; + int count = buf.readUnsignedByte(); + int tagLength = buf.readUnsignedByte(); + + for (int i = 1; i <= count; i++) { + int tagEnd = buf.readerIndex() + tagLength; + + buf.readUnsignedByte(); // status + buf.readUnsignedShortLE(); // battery voltage - buf.readUnsignedByte(); // status - buf.readUnsignedShortLE(); // battery voltage + position.set(Position.PREFIX_TEMP + i, (buf.readShortLE() & 0x3fff) * 0.1); + + buf.readUnsignedByte(); // humidity + buf.readUnsignedByte(); // rssi + + buf.readerIndex(tagEnd); + } - position.set(Position.PREFIX_TEMP + i, (buf.readShortLE() & 0x3fff) * 0.1); + } else if (type == 1) { - buf.readUnsignedByte(); // humidity - buf.readUnsignedByte(); // rssi + position.set(Position.KEY_CARD, buf.readCharSequence( + blockEnd - buf.readerIndex(), StandardCharsets.UTF_8).toString()); - buf.readerIndex(tagEnd); } } @@ -364,9 +373,9 @@ public class TzoneProtocolDecoder extends BaseProtocolDecoder { } - if (hardware == 0x406) { + if (hardware == 0x153 || hardware == 0x406) { - decodeTags(position, buf); + decodeTags(position, buf, hardware); } diff --git a/src/main/java/org/traccar/protocol/UlbotechProtocol.java b/src/main/java/org/traccar/protocol/UlbotechProtocol.java index 57fc47644..f8c4f1960 100644 --- a/src/main/java/org/traccar/protocol/UlbotechProtocol.java +++ b/src/main/java/org/traccar/protocol/UlbotechProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class UlbotechProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/UproProtocol.java b/src/main/java/org/traccar/protocol/UproProtocol.java index e27088594..cbec9777d 100644 --- a/src/main/java/org/traccar/protocol/UproProtocol.java +++ b/src/main/java/org/traccar/protocol/UproProtocol.java @@ -22,7 +22,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class UproProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java index ed714e464..8d2e5de0a 100644 --- a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java @@ -310,6 +310,10 @@ public class UproProtocolDecoder extends BaseProtocolDecoder { position.set("serial", data.toString(StandardCharsets.US_ASCII).substring(3)); } break; + case 'd': + position.set(Position.PREFIX_ADC + 1, + Integer.parseInt(data.toString(StandardCharsets.US_ASCII)) / 100.0); + break; default: break; } diff --git a/src/main/java/org/traccar/protocol/UuxProtocol.java b/src/main/java/org/traccar/protocol/UuxProtocol.java index 3de4a4732..63727cb94 100644 --- a/src/main/java/org/traccar/protocol/UuxProtocol.java +++ b/src/main/java/org/traccar/protocol/UuxProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class UuxProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/V680Protocol.java b/src/main/java/org/traccar/protocol/V680Protocol.java index 53bca849c..587a0c8f7 100644 --- a/src/main/java/org/traccar/protocol/V680Protocol.java +++ b/src/main/java/org/traccar/protocol/V680Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class V680Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/ValtrackProtocol.java b/src/main/java/org/traccar/protocol/ValtrackProtocol.java new file mode 100644 index 000000000..8471a0fd8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ValtrackProtocol.java @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +public class ValtrackProtocol extends BaseProtocol { + + @Inject + public ValtrackProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(16384)); + pipeline.addLast(new ValtrackProtocolDecoder(ValtrackProtocol.this)); + } + }); + } +} diff --git a/src/main/java/org/traccar/protocol/ValtrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/ValtrackProtocolDecoder.java new file mode 100644 index 000000000..dc9ca8590 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ValtrackProtocolDecoder.java @@ -0,0 +1,84 @@ +/* + * Copyright 2024 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.io.StringReader; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class ValtrackProtocolDecoder extends BaseHttpProtocolDecoder { + + public ValtrackProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + String content = request.content().toString(StandardCharsets.UTF_8); + JsonObject object = Json.createReader(new StringReader(content)).readObject(); + JsonArray messages = object.getJsonArray("resource"); + + List<Position> positions = new LinkedList<>(); + for (int i = 0; i < messages.size(); i++) { + + JsonObject message = messages.getJsonObject(i); + String id = message.getString("devid"); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + continue; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + position.setTime(new Date()); + position.setLatitude(Double.parseDouble(message.getString("lat"))); + position.setLongitude(Double.parseDouble(message.getString("lon"))); + String speed = message.getString("speed"); + if (!speed.isEmpty()) { + position.setSpeed(Double.parseDouble(speed)); + } + + position.set(Position.KEY_BATTERY, Double.parseDouble(message.getString("vbat"))); + + positions.add(position); + + } + + sendResponse(channel, HttpResponseStatus.OK); + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/VisiontekProtocol.java b/src/main/java/org/traccar/protocol/VisiontekProtocol.java index 5296402b4..83bcd37ff 100644 --- a/src/main/java/org/traccar/protocol/VisiontekProtocol.java +++ b/src/main/java/org/traccar/protocol/VisiontekProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class VisiontekProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/VltProtocol.java b/src/main/java/org/traccar/protocol/VltProtocol.java new file mode 100644 index 000000000..005cd8ffb --- /dev/null +++ b/src/main/java/org/traccar/protocol/VltProtocol.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +import jakarta.inject.Inject; + +public class VltProtocol extends BaseProtocol { + + @Inject + public VltProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(65535)); + pipeline.addLast(new VltProtocolDecoder(VltProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/VltProtocolDecoder.java b/src/main/java/org/traccar/protocol/VltProtocolDecoder.java new file mode 100644 index 000000000..01c0563f5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/VltProtocolDecoder.java @@ -0,0 +1,139 @@ +/* + * Copyright 2023 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.QueryStringDecoder; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; + +public class VltProtocolDecoder extends BaseHttpProtocolDecoder { + + public VltProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(dd)") // alert id + .expression("([HL])") // history + .number("([01])") // validity + .number("(dd)(dd)(dd)") // date (ddmmyy) + .number("(dd)(dd)(dd)") // time (hhmmss) + .number("(d{3}.d{6})([NS])") // latitude + .number("(d{3}.d{6})([EW])") // longitude + .number("(d{3})") // mcc + .expression("(x*[0-9]+)") // mnc + .number("(x{4})") // lac + .number("(d{9})") // cid + .number("(d{3}.d{2})") // speed + .number("(d{3}.d{2})") // course + .number("(d{2})") // satellites + .number("(d{2})") // hdop + .number("(d{2})") // rssi + .number("([01])") // ignition + .number("([01])") // charging + .expression("([HMS])") // vehicle mode + .compile(); + + private Position decodePosition(DeviceSession deviceSession, String sentence) { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_EVENT, parser.nextInt()); + position.set(Position.KEY_ARCHIVE, parser.next().equals("H") ? true : null); + + position.setValid(parser.nextInt() > 0); + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + + int mcc = parser.nextInt(); + int mnc = Integer.parseInt(parser.next().replaceAll("x", "")); + int lac = parser.nextHexInt(); + int cid = parser.nextInt(); + + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextDouble()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_HDOP, parser.nextInt()); + + position.setNetwork(new Network(CellTower.from(mcc, mnc, lac, cid, parser.nextInt()))); + + position.set(Position.KEY_IGNITION, parser.nextInt() > 0); + position.set(Position.KEY_CHARGE, parser.nextInt() > 0); + position.set(Position.KEY_MOTION, parser.next().equals("M")); + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + QueryStringDecoder decoder = new QueryStringDecoder( + request.content().toString(StandardCharsets.US_ASCII), false); + String sentence = decoder.parameters().get("vltdata").iterator().next(); + + int index = 0; + String type = sentence.substring(index, index += 3); + String imei = sentence.substring(index, index += 15); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + + sendResponse(channel, HttpResponseStatus.OK); + + switch (type) { + case "NRM": + return decodePosition(deviceSession, sentence.substring(3 + 15)); + case "BTH": + List<Position> positions = new LinkedList<>(); + int count = Integer.parseInt(sentence.substring(index, index += 3)); + for (int i = 0; i < count; i++) { + positions.add(decodePosition(deviceSession, sentence.substring(index, index += 78))); + } + return positions; + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/VnetProtocol.java b/src/main/java/org/traccar/protocol/VnetProtocol.java index dd739f0d9..6ccc54483 100644 --- a/src/main/java/org/traccar/protocol/VnetProtocol.java +++ b/src/main/java/org/traccar/protocol/VnetProtocol.java @@ -23,7 +23,7 @@ import org.traccar.config.Config; import java.nio.ByteOrder; -import javax.inject.Inject; +import jakarta.inject.Inject; public class VnetProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Vt200Protocol.java b/src/main/java/org/traccar/protocol/Vt200Protocol.java index efb5fe2fd..97e64b74f 100644 --- a/src/main/java/org/traccar/protocol/Vt200Protocol.java +++ b/src/main/java/org/traccar/protocol/Vt200Protocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Vt200Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java index a8fc801e7..1ad15f39c 100644 --- a/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java @@ -123,7 +123,7 @@ public class Vt200ProtocolDecoder extends BaseProtocolDecoder { position.set("tripStart", decodeDate(buf).getTime()); position.set("tripEnd", decodeDate(buf).getTime()); - position.set("drivingTime", buf.readUnsignedShort()); + position.set(Position.KEY_DRIVING_TIME, buf.readUnsignedShort()); position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt()); position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt()); diff --git a/src/main/java/org/traccar/protocol/VtfmsProtocol.java b/src/main/java/org/traccar/protocol/VtfmsProtocol.java index 482ab4a37..91453c413 100644 --- a/src/main/java/org/traccar/protocol/VtfmsProtocol.java +++ b/src/main/java/org/traccar/protocol/VtfmsProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class VtfmsProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/WatchFrameDecoder.java b/src/main/java/org/traccar/protocol/WatchFrameDecoder.java index f99bd52e2..9dfae8726 100644 --- a/src/main/java/org/traccar/protocol/WatchFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/WatchFrameDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2023 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. @@ -27,7 +27,26 @@ public class WatchFrameDecoder extends BaseFrameDecoder { protected Object decode( ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ']') + 1; + int brackets = 0; + int endIndex = -1; + for (int i = buf.readerIndex(); i < buf.writerIndex(); i++) { + byte b = buf.getByte(i); + switch (b) { + case '[': + brackets += 1; + break; + case ']': + brackets -= 1; + break; + default: + break; + } + if (brackets == 0 && i > buf.readerIndex()) { + endIndex = i + 1; + break; + } + } + if (endIndex > 0) { ByteBuf frame = Unpooled.buffer(); while (buf.readerIndex() < endIndex) { diff --git a/src/main/java/org/traccar/protocol/WatchProtocol.java b/src/main/java/org/traccar/protocol/WatchProtocol.java index 600f81328..aee70b6ec 100644 --- a/src/main/java/org/traccar/protocol/WatchProtocol.java +++ b/src/main/java/org/traccar/protocol/WatchProtocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class WatchProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java b/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java index 40d56b130..b586f4e92 100644 --- a/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java @@ -51,7 +51,7 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder { .number("(dd)(dd)(dd),") // time (hhmmss) .expression("([AV]),") // validity .number(" *(-?d+.d+),") // latitude - .expression("([NS]),") + .expression("([NS])?,") .number(" *(-?d+.d+),") // longitude .expression("([EW])?,") .number("(d+.?d*),") // speed @@ -285,7 +285,8 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder { || type.equalsIgnoreCase("BLOOD") || type.equalsIgnoreCase("BPHRT") || type.equalsIgnoreCase("TEMP") - || type.equalsIgnoreCase("btemp2")) { + || type.equalsIgnoreCase("btemp2") + || type.equalsIgnoreCase("oxygen")) { if (buf.isReadable()) { @@ -303,6 +304,8 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder { if (Integer.parseInt(values[valueIndex++]) > 0) { position.set(Position.PREFIX_TEMP + 1, Double.parseDouble(values[valueIndex])); } + } else if (type.equalsIgnoreCase("oxygen")) { + position.set("bloodOxygen", Integer.parseInt(values[++valueIndex])); } else { if (type.equalsIgnoreCase("BPHRT") || type.equalsIgnoreCase("BLOOD")) { position.set("pressureHigh", values[valueIndex++]); diff --git a/src/main/java/org/traccar/protocol/WialonProtocol.java b/src/main/java/org/traccar/protocol/WialonProtocol.java index a744349cd..84033132d 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocol.java +++ b/src/main/java/org/traccar/protocol/WialonProtocol.java @@ -27,7 +27,7 @@ import org.traccar.model.Command; import java.nio.charset.StandardCharsets; -import javax.inject.Inject; +import jakarta.inject.Inject; public class WialonProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java index 3d57525b7..4d1b34dba 100644 --- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java @@ -63,8 +63,9 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { .number("(?:NA|(d+));") // outputs .expression("(?:NA|([^;]*));") // adc .expression("(?:NA|([^;]*));") // ibutton - .expression("(?:NA|(.*))") // params + .expression("(?:NA|([^;]*))") // params .groupEnd("?") + .any() .compile(); private void sendResponse(Channel channel, SocketAddress remoteAddress, String type, Integer number) { @@ -101,7 +102,7 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { position.setTime(new Date()); } - if (parser.hasNext(9)) { + if (parser.hasNextAny(9)) { position.setLatitude(parser.nextCoordinate()); position.setLongitude(parser.nextCoordinate()); position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); @@ -135,10 +136,22 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder { for (String param : values) { Matcher paramParser = Pattern.compile("(.*):[1-3]:(.*)").matcher(param); if (paramParser.matches()) { + String key = paramParser.group(1).toLowerCase(); + String value = paramParser.group(2); try { - position.set(paramParser.group(1).toLowerCase(), Double.parseDouble(paramParser.group(2))); + if (key.equals("accuracy")) { + position.setAccuracy(Double.parseDouble(value)); + } else { + position.set(key, Double.parseDouble(value)); + } } catch (NumberFormatException e) { - position.set(paramParser.group(1).toLowerCase(), paramParser.group(2)); + if (value.equalsIgnoreCase("true")) { + position.set(key, true); + } else if (value.equalsIgnoreCase("false")) { + position.set(key, false); + } else { + position.set(key, value); + } } } } diff --git a/src/main/java/org/traccar/protocol/WliProtocol.java b/src/main/java/org/traccar/protocol/WliProtocol.java index f7084e55b..5b9ebb520 100644 --- a/src/main/java/org/traccar/protocol/WliProtocol.java +++ b/src/main/java/org/traccar/protocol/WliProtocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class WliProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/WondexProtocol.java b/src/main/java/org/traccar/protocol/WondexProtocol.java index 5a0401df4..e27b8e2bb 100644 --- a/src/main/java/org/traccar/protocol/WondexProtocol.java +++ b/src/main/java/org/traccar/protocol/WondexProtocol.java @@ -22,7 +22,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class WondexProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/WristbandProtocol.java b/src/main/java/org/traccar/protocol/WristbandProtocol.java index c5d8d4050..117daf8cf 100644 --- a/src/main/java/org/traccar/protocol/WristbandProtocol.java +++ b/src/main/java/org/traccar/protocol/WristbandProtocol.java @@ -21,7 +21,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class WristbandProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Xexun2Protocol.java b/src/main/java/org/traccar/protocol/Xexun2Protocol.java index 52cf731f0..9dd517cfa 100644 --- a/src/main/java/org/traccar/protocol/Xexun2Protocol.java +++ b/src/main/java/org/traccar/protocol/Xexun2Protocol.java @@ -21,7 +21,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Xexun2Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java index 913dfaf28..0e3c44e12 100644 --- a/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java @@ -156,7 +156,7 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder { for (int j = 0; j < wifiCount; j++) { String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); network.addWifiAccessPoint(WifiAccessPoint.from( - mac.substring(0, mac.length() - 1), buf.readUnsignedByte())); + mac.substring(0, mac.length() - 1), buf.readByte())); } } if (BitUtil.check(positionMask, 2)) { @@ -164,7 +164,7 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder { for (int j = 0; j < cellCount; j++) { network.addCellTower(CellTower.from( buf.readUnsignedShort(), buf.readUnsignedShort(), - buf.readInt(), buf.readUnsignedInt(), buf.readUnsignedByte())); + buf.readInt(), buf.readUnsignedInt(), buf.readByte())); } } if (network.getWifiAccessPoints() != null || network.getCellTowers() != null) { diff --git a/src/main/java/org/traccar/protocol/XexunProtocol.java b/src/main/java/org/traccar/protocol/XexunProtocol.java index 5c7329603..e76e47d19 100644 --- a/src/main/java/org/traccar/protocol/XexunProtocol.java +++ b/src/main/java/org/traccar/protocol/XexunProtocol.java @@ -25,7 +25,7 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class XexunProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/XirgoProtocol.java b/src/main/java/org/traccar/protocol/XirgoProtocol.java index 0841d86d5..7e14c6842 100644 --- a/src/main/java/org/traccar/protocol/XirgoProtocol.java +++ b/src/main/java/org/traccar/protocol/XirgoProtocol.java @@ -24,7 +24,7 @@ import org.traccar.TrackerServer; import org.traccar.config.Config; import org.traccar.model.Command; -import javax.inject.Inject; +import jakarta.inject.Inject; public class XirgoProtocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Xrb28Protocol.java b/src/main/java/org/traccar/protocol/Xrb28Protocol.java index 65c2a1230..135fb0928 100644 --- a/src/main/java/org/traccar/protocol/Xrb28Protocol.java +++ b/src/main/java/org/traccar/protocol/Xrb28Protocol.java @@ -26,7 +26,7 @@ import org.traccar.model.Command; import java.nio.charset.StandardCharsets; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Xrb28Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java index 88f2d07e5..6033293c4 100644 --- a/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2024 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. @@ -27,6 +27,7 @@ import org.traccar.model.Command; import org.traccar.model.Position; import java.net.SocketAddress; +import java.util.Arrays; import java.util.regex.Pattern; public class Xrb28ProtocolDecoder extends BaseProtocolDecoder { @@ -46,6 +47,7 @@ public class Xrb28ProtocolDecoder extends BaseProtocolDecoder { .expression("....,") .expression("..,") // vendor .number("d{15},") // imei + .number("d{12},").optional() // time .expression("..,") // type .number("[01],") // reserved .number("(dd)(dd)(dd).d+,") // time (hhmmss) @@ -67,23 +69,44 @@ public class Xrb28ProtocolDecoder extends BaseProtocolDecoder { Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { String sentence = (String) msg; + String[] values = sentence.replaceAll("#$", "").split(","); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(9, 24)); + int index = 0; + String header = values[index++]; + String vendor = values[index++]; + + String imei = values[index++]; + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); if (deviceSession == null) { return null; } - String type = sentence.substring(25, 27); + String time; + if (values[index].length() == 12) { + time = values[index++]; + } else { + time = null; + } + + String type = values[index++]; if (channel != null) { + StringBuilder response = new StringBuilder("\u00ff\u00ff"); + response.append(header.replaceAll("R$", "S")).append(','); + response.append(vendor).append(','); + response.append(imei).append(','); + if (time != null) { + response.append(time).append(','); + } if (type.matches("L0|L1|W0|E1")) { - channel.write(new NetworkMessage( - "\u00ff\u00ff*SCOS" + sentence.substring(5, 27) + "#\n", - remoteAddress)); + response.append(type).append("#\n"); + channel.write(new NetworkMessage(response.toString(), remoteAddress)); } else if (type.equals("R0") && pendingCommand != null) { - String command = pendingCommand.equals(Command.TYPE_ALARM_ARM) ? "L1," : "L0,"; - channel.write(new NetworkMessage( - "\u00ff\u00ff*SCOS" + sentence.substring(5, 25) + command + sentence.substring(30) + "\n", - remoteAddress)); + String command = pendingCommand.equals(Command.TYPE_ALARM_ARM) ? "L1" : "L0"; + response.append(command); + String[] remaining = Arrays.copyOfRange(values, index, values.length); + response.append(String.join(",", remaining)); + response.append("#\n"); + channel.write(new NetworkMessage(response.toString(), remoteAddress)); pendingCommand = null; } } @@ -95,11 +118,6 @@ public class Xrb28ProtocolDecoder extends BaseProtocolDecoder { getLastLocation(position, null); - String payload = sentence.substring(25, sentence.length() - 1); - - int index = 0; - String[] values = payload.substring(3).split(","); - switch (type) { case "Q0": position.set(Position.KEY_BATTERY, Integer.parseInt(values[index++]) * 0.01); @@ -146,7 +164,8 @@ public class Xrb28ProtocolDecoder extends BaseProtocolDecoder { case "K0": case "I0": case "M0": - position.set(Position.KEY_RESULT, payload); + String[] remaining = Arrays.copyOfRange(values, index, values.length); + position.set(Position.KEY_RESULT, String.join(",", remaining)); break; default: break; diff --git a/src/main/java/org/traccar/protocol/Xt013Protocol.java b/src/main/java/org/traccar/protocol/Xt013Protocol.java index 9e9087609..25809463a 100644 --- a/src/main/java/org/traccar/protocol/Xt013Protocol.java +++ b/src/main/java/org/traccar/protocol/Xt013Protocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Xt013Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Xt2400Protocol.java b/src/main/java/org/traccar/protocol/Xt2400Protocol.java index e200adb9f..1b7fc840b 100644 --- a/src/main/java/org/traccar/protocol/Xt2400Protocol.java +++ b/src/main/java/org/traccar/protocol/Xt2400Protocol.java @@ -20,7 +20,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class Xt2400Protocol extends BaseProtocol { diff --git a/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java index edcb3f535..11f9e0654 100644 --- a/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java @@ -177,7 +177,7 @@ public class Xt2400ProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.1); break; case 0x57: - position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort()); break; case 0x65: position.set(Position.KEY_VIN, buf.readSlice(17).toString(StandardCharsets.US_ASCII)); diff --git a/src/main/java/org/traccar/protocol/YwtProtocol.java b/src/main/java/org/traccar/protocol/YwtProtocol.java index fb44e2360..27c71cfa8 100644 --- a/src/main/java/org/traccar/protocol/YwtProtocol.java +++ b/src/main/java/org/traccar/protocol/YwtProtocol.java @@ -23,7 +23,7 @@ import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import javax.inject.Inject; +import jakarta.inject.Inject; public class YwtProtocol extends BaseProtocol { |