From 1359371f83393e4a6a5dcbc0df03ab1b33bebde5 Mon Sep 17 00:00:00 2001 From: anton2920 Date: Sun, 24 Jul 2022 17:32:01 +0100 Subject: Added high-level payload parsing --- .../traccar/protocol/PiligrimProtocolDecoder.java | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index 244df6806..dca8b1329 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -30,6 +30,7 @@ import org.traccar.model.Position; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -150,6 +151,33 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { } return positions; + } else if (uri.startsWith("/push.do")) { + /* Getting payload */ + ByteBuf content_stream = request.content(); + byte[] payload_bytes = new byte[Integer.parseInt(request.headers().get("Content-Length"))]; + content_stream.readBytes(payload_bytes); + String payload = new String(payload_bytes); + + /* Payload structure: + * &phone&message + */ + String[] payload_parts = payload.split("&"); + System.out.println("Payload parts: " + Arrays.toString(payload_parts)); + String phone_number = payload_parts[1].substring(12); + String message = payload_parts[2].substring(8); + System.out.println("Phone number: " + phone_number); + System.out.println("Message: " + message); + + /* Supported message structure: + * GPS NMEA Command; GSM info; Unknown; Battery voltage? + */ + if (message.startsWith("$GPRMC")) { + System.out.println("Supported message"); + } else { + System.out.println("Unsupported message"); + } + + System.out.println("Finish"); } return null; -- cgit v1.2.3 From 16197c4bec4da40372da7505c6b2093da6b743f5 Mon Sep 17 00:00:00 2001 From: anton2920 Date: Sun, 24 Jul 2022 17:47:13 +0100 Subject: Added high-level parsing of message field --- .../traccar/protocol/PiligrimProtocolDecoder.java | 23 +++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index dca8b1329..29b6d9ef0 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -168,11 +168,28 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { System.out.println("Phone number: " + phone_number); System.out.println("Message: " + message); - /* Supported message structure: - * GPS NMEA Command; GSM info; Unknown; Battery voltage? - */ if (message.startsWith("$GPRMC")) { + /* Supported message structure: + * GPS NMEA Command; GSM info; Unknown; Battery voltage? + * Example: $GPRMC,180752.000,A,5314.0857,N,03421.8173,E,0.00,104.74,220722,,,A,V* 29,05; GSM: 250-01 0b54-0519,1c30,3e96,3ebe,412e 25; S; Batt: 405,M + */ System.out.println("Supported message"); + + String[] message_parts = message.split(";"); + System.out.println("Message parts: " + Arrays.toString(message_parts)); + + /* Parsing GPS */ + String unprocessed_gps_command = message_parts[0]; + + /* Getting rid of checksum */ + String gps_command = unprocessed_gps_command.replaceFirst("A,V[*].*", ""); + System.out.println("GPS command: " + gps_command); + + /* Parsing other fields */ + /* String gsm_info = message_parts[1]; */ + /* String unknown = message_parts[2]; */ + String battery_info = message_parts[3].substring(7).substring(0, 3); + System.out.println("Battery: " + battery_info); } else { System.out.println("Unsupported message"); } -- cgit v1.2.3 From 3ead0772172daeb3d6fedab5f04a32c33b9d5ebb Mon Sep 17 00:00:00 2001 From: anton2920 Date: Sun, 24 Jul 2022 17:53:21 +0100 Subject: Added NMEA parser (that doesn't s**ck) --- src/main/java/org/traccar/helper/NMEA.java | 126 +++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/main/java/org/traccar/helper/NMEA.java diff --git a/src/main/java/org/traccar/helper/NMEA.java b/src/main/java/org/traccar/helper/NMEA.java new file mode 100644 index 000000000..cae47a8f6 --- /dev/null +++ b/src/main/java/org/traccar/helper/NMEA.java @@ -0,0 +1,126 @@ +package org.traccar.helper; + +import java.util.HashMap; +import java.util.Map; + + +public class NMEA { + + // fucking java interfaces + interface SentenceParser { + public boolean parse(String[] tokens, GPSPosition position); + } + + // utils + static float Latitude2Decimal(String lat, String NS) { + float med = Float.parseFloat(lat.substring(2)) / 60.0f; + med += Float.parseFloat(lat.substring(0, 2)); + if (NS.startsWith("S")) { + med = -med; + } + return med; + } + + static float Longitude2Decimal(String lon, String WE) { + float med = Float.parseFloat(lon.substring(3)) / 60.0f; + med += Float.parseFloat(lon.substring(0, 3)); + if (WE.startsWith("W")) { + med = -med; + } + return med; + } + + // parsers + class GPGGA implements SentenceParser { + public boolean parse(String[] tokens, GPSPosition position) { + position.time = Float.parseFloat(tokens[1]); + position.lat = Latitude2Decimal(tokens[2], tokens[3]); + position.lon = Longitude2Decimal(tokens[4], tokens[5]); + position.quality = Integer.parseInt(tokens[6]); + position.altitude = Float.parseFloat(tokens[9]); + return true; + } + } + + class GPGGL implements SentenceParser { + public boolean parse(String[] tokens, GPSPosition position) { + position.lat = Latitude2Decimal(tokens[1], tokens[2]); + position.lon = Longitude2Decimal(tokens[3], tokens[4]); + position.time = Float.parseFloat(tokens[5]); + return true; + } + } + + class GPRMC implements SentenceParser { + public boolean parse(String[] tokens, GPSPosition position) { + position.time = Float.parseFloat(tokens[1]); + position.lat = Latitude2Decimal(tokens[3], tokens[4]); + position.lon = Longitude2Decimal(tokens[5], tokens[6]); + position.velocity = Float.parseFloat(tokens[7]); + position.dir = Float.parseFloat(tokens[8]); + return true; + } + } + + class GPVTG implements SentenceParser { + public boolean parse(String[] tokens, GPSPosition position) { + position.dir = Float.parseFloat(tokens[3]); + return true; + } + } + + class GPRMZ implements SentenceParser { + public boolean parse(String[] tokens, GPSPosition position) { + position.altitude = Float.parseFloat(tokens[1]); + return true; + } + } + + public class GPSPosition { + public float time = 0.0f; + public float lat = 0.0f; + public float lon = 0.0f; + public boolean fixed = false; + public int quality = 0; + public float dir = 0.0f; + public float altitude = 0.0f; + public float velocity = 0.0f; + + public void updatefix() { + fixed = quality > 0; + } + + public String toString() { + return String.format("POSITION: lat: %f, lon: %f, time: %f, Q: %d, dir: %f, alt: %f, vel: %f", lat, lon, time, quality, dir, altitude, velocity); + } + } + + GPSPosition position = new GPSPosition(); + + private static final Map sentenceParsers = new HashMap(); + + public NMEA() { + sentenceParsers.put("GPGGA", new GPGGA()); + sentenceParsers.put("GPGGL", new GPGGL()); + sentenceParsers.put("GPRMC", new GPRMC()); + sentenceParsers.put("GPRMZ", new GPRMZ()); + //only really good GPS devices have this sentence but ... + sentenceParsers.put("GPVTG", new GPVTG()); + } + + public GPSPosition parse(String line) { + + if (line.startsWith("$")) { + String nmea = line.substring(1); + String[] tokens = nmea.split(","); + String type = tokens[0]; + //TODO check crc + if (sentenceParsers.containsKey(type)) { + sentenceParsers.get(type).parse(tokens, position); + } + position.updatefix(); + } + + return position; + } +} -- cgit v1.2.3 From 2274b42c6b1c7b1ef90e3ec4e5e956afe66eaa6d Mon Sep 17 00:00:00 2001 From: anton2920 Date: Sun, 24 Jul 2022 18:01:41 +0100 Subject: Added parsing of GPS NMEA message --- .../java/org/traccar/protocol/PiligrimProtocolDecoder.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index 29b6d9ef0..7f9d20822 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -26,6 +26,7 @@ import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.helper.BitUtil; import org.traccar.helper.DateBuilder; +import org.traccar.helper.NMEA; import org.traccar.model.Position; import java.net.SocketAddress; @@ -163,7 +164,7 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { */ String[] payload_parts = payload.split("&"); System.out.println("Payload parts: " + Arrays.toString(payload_parts)); - String phone_number = payload_parts[1].substring(12); + String phone_number = payload_parts[1].substring(15); String message = payload_parts[2].substring(8); System.out.println("Phone number: " + phone_number); System.out.println("Message: " + message); @@ -185,6 +186,14 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { String gps_command = unprocessed_gps_command.replaceFirst("A,V[*].*", ""); System.out.println("GPS command: " + gps_command); + NMEA gps_parser = new NMEA(); + + NMEA.GPSPosition gps_position = gps_parser.parse(gps_command); + + System.out.println("Time: " + gps_position.time); + System.out.println("Coordinates: " + gps_position.lat + " " + gps_position.lon); + System.out.println("Speed over ground: " + gps_position.velocity + " knots"); + /* Parsing other fields */ /* String gsm_info = message_parts[1]; */ /* String unknown = message_parts[2]; */ -- cgit v1.2.3 From 62b38f2ccf0db60e7e953485898a1d3bf5c452e0 Mon Sep 17 00:00:00 2001 From: anton2920 Date: Sun, 24 Jul 2022 18:36:33 +0100 Subject: WIP: Added position return --- .../traccar/protocol/PiligrimProtocolDecoder.java | 28 ++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index 7f9d20822..967adb82b 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -21,6 +21,7 @@ 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 net.fortuna.ical4j.model.DateTime; import org.traccar.BaseHttpProtocolDecoder; import org.traccar.session.DeviceSession; import org.traccar.Protocol; @@ -32,6 +33,7 @@ import org.traccar.model.Position; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Date; import java.util.LinkedList; import java.util.List; @@ -153,6 +155,13 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { return positions; } else if (uri.startsWith("/push.do")) { + sendResponse(channel, "PUSH.DO: OK"); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, "123456"); + if (deviceSession == null) { + return null; + } + /* Getting payload */ ByteBuf content_stream = request.content(); byte[] payload_bytes = new byte[Integer.parseInt(request.headers().get("Content-Length"))]; @@ -199,11 +208,26 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { /* String unknown = message_parts[2]; */ String battery_info = message_parts[3].substring(7).substring(0, 3); System.out.println("Battery: " + battery_info); + + /* Constructing response */ + Position position = new Position(getProtocolName()); + + position.setDeviceId(deviceSession.getDeviceId()); + position.setValid(true); + position.setLatitude(gps_position.lat); + position.setLongitude(gps_position.lon); + position.setTime(new Date(System.currentTimeMillis())); + position.setSpeed(gps_position.velocity); + position.setCourse(gps_position.dir); + position.setAccuracy(gps_position.quality); + position.set(Position.KEY_BATTERY, Integer.parseInt(battery_info) / 100); + + System.out.println("Supported message finish"); + + return position; } else { System.out.println("Unsupported message"); } - - System.out.println("Finish"); } return null; -- cgit v1.2.3 From b66d4c3b3250edac4762176277f4f07bc2e74d8e Mon Sep 17 00:00:00 2001 From: anton2920 Date: Sun, 24 Jul 2022 18:43:30 +0100 Subject: Commented out 'System.out.println()'s --- .../org/traccar/protocol/PiligrimProtocolDecoder.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index 967adb82b..775032b64 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -172,11 +172,11 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { * &phone&message */ String[] payload_parts = payload.split("&"); - System.out.println("Payload parts: " + Arrays.toString(payload_parts)); + /* System.out.println("Payload parts: " + Arrays.toString(payload_parts)); */ String phone_number = payload_parts[1].substring(15); String message = payload_parts[2].substring(8); - System.out.println("Phone number: " + phone_number); - System.out.println("Message: " + message); + /* System.out.println("Phone number: " + phone_number); */ + /* System.out.println("Message: " + message); */ if (message.startsWith("$GPRMC")) { /* Supported message structure: @@ -186,28 +186,28 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { System.out.println("Supported message"); String[] message_parts = message.split(";"); - System.out.println("Message parts: " + Arrays.toString(message_parts)); + /* System.out.println("Message parts: " + Arrays.toString(message_parts)); */ /* Parsing GPS */ String unprocessed_gps_command = message_parts[0]; /* Getting rid of checksum */ String gps_command = unprocessed_gps_command.replaceFirst("A,V[*].*", ""); - System.out.println("GPS command: " + gps_command); + /* System.out.println("GPS command: " + gps_command); */ NMEA gps_parser = new NMEA(); NMEA.GPSPosition gps_position = gps_parser.parse(gps_command); - System.out.println("Time: " + gps_position.time); - System.out.println("Coordinates: " + gps_position.lat + " " + gps_position.lon); - System.out.println("Speed over ground: " + gps_position.velocity + " knots"); + /* System.out.println("Time: " + gps_position.time); */ + /* System.out.println("Coordinates: " + gps_position.lat + " " + gps_position.lon); */ + /* System.out.println("Speed over ground: " + gps_position.velocity + " knots"); */ /* Parsing other fields */ /* String gsm_info = message_parts[1]; */ /* String unknown = message_parts[2]; */ String battery_info = message_parts[3].substring(7).substring(0, 3); - System.out.println("Battery: " + battery_info); + /* System.out.println("Battery: " + battery_info); */ /* Constructing response */ Position position = new Position(getProtocolName()); -- cgit v1.2.3 From 26e3d616ef17db2c30da0e9c8c0a7a1e9182cc6c Mon Sep 17 00:00:00 2001 From: anton2920 Date: Sun, 24 Jul 2022 19:18:49 +0100 Subject: Added workaround for 'ALARM KEY;' --- src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index 775032b64..d1f667f6f 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -173,8 +173,8 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { */ String[] payload_parts = payload.split("&"); /* System.out.println("Payload parts: " + Arrays.toString(payload_parts)); */ - String phone_number = payload_parts[1].substring(15); - String message = payload_parts[2].substring(8); + /* String phone_number = payload_parts[1].substring(15); */ + String message = payload_parts[2].substring(8).replaceFirst("ALARM KEY; ", ""); /* System.out.println("Phone number: " + phone_number); */ /* System.out.println("Message: " + message); */ @@ -220,6 +220,7 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { position.setSpeed(gps_position.velocity); position.setCourse(gps_position.dir); position.setAccuracy(gps_position.quality); + position.setAltitude(gps_position.altitude); position.set(Position.KEY_BATTERY, Integer.parseInt(battery_info) / 100); System.out.println("Supported message finish"); -- cgit v1.2.3 From b3caf3c1cee6cb665e8ac05be35d9258c353771e Mon Sep 17 00:00:00 2001 From: anton2920 Date: Tue, 6 Sep 2022 10:53:38 +0100 Subject: Replaced hard-coded ID with phone number --- .../org/traccar/protocol/PiligrimProtocolDecoder.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index d1f667f6f..da8991bd3 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -157,11 +157,6 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { } else if (uri.startsWith("/push.do")) { sendResponse(channel, "PUSH.DO: OK"); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, "123456"); - if (deviceSession == null) { - return null; - } - /* Getting payload */ ByteBuf content_stream = request.content(); byte[] payload_bytes = new byte[Integer.parseInt(request.headers().get("Content-Length"))]; @@ -173,7 +168,15 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { */ String[] payload_parts = payload.split("&"); /* System.out.println("Payload parts: " + Arrays.toString(payload_parts)); */ - /* String phone_number = payload_parts[1].substring(15); */ + String phone_number = payload_parts[1].substring(15); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, phone_number); + if (deviceSession == null) { + return null; + } + + /* TODO: generalize this process; + * TODO: use keys for flags in 'positions'. + */ String message = payload_parts[2].substring(8).replaceFirst("ALARM KEY; ", ""); /* System.out.println("Phone number: " + phone_number); */ /* System.out.println("Message: " + message); */ -- cgit v1.2.3 From bd49d52fc47dcb902b9fb2b3e8cf82d9550a025c Mon Sep 17 00:00:00 2001 From: anton2920 Date: Tue, 6 Sep 2022 10:58:20 +0100 Subject: Refactored naming convention to 'camelCase' and changed 'System.out.println' to 'LOGGER.info' --- .../traccar/protocol/PiligrimProtocolDecoder.java | 77 +++++++++++----------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index da8991bd3..0a22e30c5 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -21,8 +21,10 @@ 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 net.fortuna.ical4j.model.DateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.WebDataHandler; import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.helper.BitUtil; @@ -32,13 +34,14 @@ import org.traccar.model.Position; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.Date; import java.util.LinkedList; import java.util.List; public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { + private static final Logger LOGGER = LoggerFactory.getLogger(WebDataHandler.class); + public PiligrimProtocolDecoder(Protocol protocol) { super(protocol); } @@ -158,18 +161,18 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { sendResponse(channel, "PUSH.DO: OK"); /* Getting payload */ - ByteBuf content_stream = request.content(); - byte[] payload_bytes = new byte[Integer.parseInt(request.headers().get("Content-Length"))]; - content_stream.readBytes(payload_bytes); - String payload = new String(payload_bytes); + ByteBuf contentStream = request.content(); + byte[] payloadBytes = new byte[Integer.parseInt(request.headers().get("Content-Length"))]; + contentStream.readBytes(payloadBytes); + String payload = new String(payloadBytes); /* Payload structure: * &phone&message */ - String[] payload_parts = payload.split("&"); - /* System.out.println("Payload parts: " + Arrays.toString(payload_parts)); */ - String phone_number = payload_parts[1].substring(15); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, phone_number); + String[] payloadParts = payload.split("&"); + /* LOGGER.info("Payload parts: " + Arrays.toString(payloadParts)); */ + String phoneNumber = payloadParts[1].substring(15); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, phoneNumber); if (deviceSession == null) { return null; } @@ -177,60 +180,60 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { /* TODO: generalize this process; * TODO: use keys for flags in 'positions'. */ - String message = payload_parts[2].substring(8).replaceFirst("ALARM KEY; ", ""); - /* System.out.println("Phone number: " + phone_number); */ - /* System.out.println("Message: " + message); */ + String message = payloadParts[2].substring(8).replaceFirst("ALARM KEY; ", ""); + /* LOGGER.info("Phone number: " + phoneNumber); */ + /* LOGGER.info("Message: " + message); */ if (message.startsWith("$GPRMC")) { /* Supported message structure: * GPS NMEA Command; GSM info; Unknown; Battery voltage? * Example: $GPRMC,180752.000,A,5314.0857,N,03421.8173,E,0.00,104.74,220722,,,A,V* 29,05; GSM: 250-01 0b54-0519,1c30,3e96,3ebe,412e 25; S; Batt: 405,M */ - System.out.println("Supported message"); + LOGGER.info("Supported message"); - String[] message_parts = message.split(";"); - /* System.out.println("Message parts: " + Arrays.toString(message_parts)); */ + String[] messageParts = message.split(";"); + /* LOGGER.info("Message parts: " + Arrays.toString(messageParts)); */ /* Parsing GPS */ - String unprocessed_gps_command = message_parts[0]; + String unprocessedGpsCommand = messageParts[0]; /* Getting rid of checksum */ - String gps_command = unprocessed_gps_command.replaceFirst("A,V[*].*", ""); - /* System.out.println("GPS command: " + gps_command); */ + String gpsCommand = unprocessedGpsCommand.replaceFirst("A,V[*].*", ""); + /* LOGGER.info("GPS command: " + gpsCommand); */ - NMEA gps_parser = new NMEA(); + NMEA gpsParser = new NMEA(); - NMEA.GPSPosition gps_position = gps_parser.parse(gps_command); + NMEA.GPSPosition gpsPosition = gpsParser.parse(gpsCommand); - /* System.out.println("Time: " + gps_position.time); */ - /* System.out.println("Coordinates: " + gps_position.lat + " " + gps_position.lon); */ - /* System.out.println("Speed over ground: " + gps_position.velocity + " knots"); */ + /* LOGGER.info("Time: " + gpsPosition.time); */ + /* LOGGER.info("Coordinates: " + gpsPosition.lat + " " + gpsPosition.lon); */ + /* LOGGER.info("Speed over ground: " + gpsPosition.velocity + " knots"); */ /* Parsing other fields */ - /* String gsm_info = message_parts[1]; */ - /* String unknown = message_parts[2]; */ - String battery_info = message_parts[3].substring(7).substring(0, 3); - /* System.out.println("Battery: " + battery_info); */ + /* String gsmInfo = messageParts[1]; */ + /* String unknown = messageParts[2]; */ + String batteryInfo = messageParts[3].substring(7).substring(0, 3); + /* LOGGER.info("Battery: " + batteryInfo); */ /* Constructing response */ Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); position.setValid(true); - position.setLatitude(gps_position.lat); - position.setLongitude(gps_position.lon); + position.setLatitude(gpsPosition.lat); + position.setLongitude(gpsPosition.lon); position.setTime(new Date(System.currentTimeMillis())); - position.setSpeed(gps_position.velocity); - position.setCourse(gps_position.dir); - position.setAccuracy(gps_position.quality); - position.setAltitude(gps_position.altitude); - position.set(Position.KEY_BATTERY, Integer.parseInt(battery_info) / 100); + position.setSpeed(gpsPosition.velocity); + position.setCourse(gpsPosition.dir); + position.setAccuracy(gpsPosition.quality); + position.setAltitude(gpsPosition.altitude); + position.set(Position.KEY_BATTERY, Integer.parseInt(batteryInfo) / 100); - System.out.println("Supported message finish"); + LOGGER.info("Supported message finish"); return position; } else { - System.out.println("Unsupported message"); + LOGGER.info("Unsupported message"); } } -- cgit v1.2.3 From 55ac4060c38b2ea6e583cbef570f4b9ec35d8b15 Mon Sep 17 00:00:00 2001 From: anton2920 Date: Tue, 6 Sep 2022 11:18:57 +0100 Subject: Changed regex for replacing event keys --- src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index 0a22e30c5..ca6b667cd 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -172,15 +172,13 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { String[] payloadParts = payload.split("&"); /* LOGGER.info("Payload parts: " + Arrays.toString(payloadParts)); */ String phoneNumber = payloadParts[1].substring(15); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, phoneNumber); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, phoneNumber.substring(1)); if (deviceSession == null) { return null; } - /* TODO: generalize this process; - * TODO: use keys for flags in 'positions'. - */ - String message = payloadParts[2].substring(8).replaceFirst("ALARM KEY; ", ""); + /* TODO: use keys for flags in 'positions'. */ + String message = payloadParts[2].substring(8).replaceFirst("[A-Z]* KEY; ", ""); /* LOGGER.info("Phone number: " + phoneNumber); */ /* LOGGER.info("Message: " + message); */ -- cgit v1.2.3 From 278f8c934ec440a6472d467688bfa1c42078bbac Mon Sep 17 00:00:00 2001 From: anton2920 Date: Wed, 7 Sep 2022 09:46:48 +0100 Subject: Fixed regex for replacing event keys --- src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index ca6b667cd..6b3b35eee 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -178,7 +178,7 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { } /* TODO: use keys for flags in 'positions'. */ - String message = payloadParts[2].substring(8).replaceFirst("[A-Z]* KEY; ", ""); + String message = payloadParts[2].substring(8).replaceFirst("[a-zA-Z! ]*; ", ""); /* LOGGER.info("Phone number: " + phoneNumber); */ /* LOGGER.info("Message: " + message); */ @@ -210,7 +210,7 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { /* Parsing other fields */ /* String gsmInfo = messageParts[1]; */ /* String unknown = messageParts[2]; */ - String batteryInfo = messageParts[3].substring(7).substring(0, 3); + String batteryInfo = messageParts[messageParts.length - 1].substring(7).substring(0, 3); /* LOGGER.info("Battery: " + batteryInfo); */ /* Constructing response */ @@ -231,7 +231,7 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { return position; } else { - LOGGER.info("Unsupported message"); + LOGGER.error("Unsupported message"); } } -- cgit v1.2.3 From e5c73ce4fcfc67f13a9151a130783b31cef76293 Mon Sep 17 00:00:00 2001 From: anton2920 Date: Wed, 7 Sep 2022 09:47:47 +0100 Subject: Moved logger messages to debug logs --- .../traccar/protocol/PiligrimProtocolDecoder.java | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index 6b3b35eee..6ca9b0795 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -170,7 +170,7 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { * &phone&message */ String[] payloadParts = payload.split("&"); - /* LOGGER.info("Payload parts: " + Arrays.toString(payloadParts)); */ + /* LOGGER.debug("Payload parts: " + Arrays.toString(payloadParts)); */ String phoneNumber = payloadParts[1].substring(15); DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, phoneNumber.substring(1)); if (deviceSession == null) { @@ -179,39 +179,39 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { /* TODO: use keys for flags in 'positions'. */ String message = payloadParts[2].substring(8).replaceFirst("[a-zA-Z! ]*; ", ""); - /* LOGGER.info("Phone number: " + phoneNumber); */ - /* LOGGER.info("Message: " + message); */ + /* LOGGER.debug("Phone number: " + phoneNumber); */ + /* LOGGER.debug("Message: " + message); */ if (message.startsWith("$GPRMC")) { /* Supported message structure: * GPS NMEA Command; GSM info; Unknown; Battery voltage? * Example: $GPRMC,180752.000,A,5314.0857,N,03421.8173,E,0.00,104.74,220722,,,A,V* 29,05; GSM: 250-01 0b54-0519,1c30,3e96,3ebe,412e 25; S; Batt: 405,M */ - LOGGER.info("Supported message"); + LOGGER.debug("Supported message"); String[] messageParts = message.split(";"); - /* LOGGER.info("Message parts: " + Arrays.toString(messageParts)); */ + /* LOGGER.debug("Message parts: " + Arrays.toString(messageParts)); */ /* Parsing GPS */ String unprocessedGpsCommand = messageParts[0]; /* Getting rid of checksum */ String gpsCommand = unprocessedGpsCommand.replaceFirst("A,V[*].*", ""); - /* LOGGER.info("GPS command: " + gpsCommand); */ + /* LOGGER.debug("GPS command: " + gpsCommand); */ NMEA gpsParser = new NMEA(); NMEA.GPSPosition gpsPosition = gpsParser.parse(gpsCommand); - /* LOGGER.info("Time: " + gpsPosition.time); */ - /* LOGGER.info("Coordinates: " + gpsPosition.lat + " " + gpsPosition.lon); */ - /* LOGGER.info("Speed over ground: " + gpsPosition.velocity + " knots"); */ + /* LOGGER.debug("Time: " + gpsPosition.time); */ + /* LOGGER.debug("Coordinates: " + gpsPosition.lat + " " + gpsPosition.lon); */ + /* LOGGER.debug("Speed over ground: " + gpsPosition.velocity + " knots"); */ /* Parsing other fields */ /* String gsmInfo = messageParts[1]; */ /* String unknown = messageParts[2]; */ String batteryInfo = messageParts[messageParts.length - 1].substring(7).substring(0, 3); - /* LOGGER.info("Battery: " + batteryInfo); */ + /* LOGGER.debug("Battery: " + batteryInfo); */ /* Constructing response */ Position position = new Position(getProtocolName()); @@ -227,7 +227,7 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { position.setAltitude(gpsPosition.altitude); position.set(Position.KEY_BATTERY, Integer.parseInt(batteryInfo) / 100); - LOGGER.info("Supported message finish"); + LOGGER.debug("Supported message finish"); return position; } else { -- cgit v1.2.3 From d4513fa86539577e24ede46d40748d8d034b025c Mon Sep 17 00:00:00 2001 From: anton2920 Date: Tue, 6 Sep 2022 10:47:37 +0100 Subject: Added support for NDTPv6 protocol --- setup/default.xml | 1 + .../org/traccar/protocol/NDTPv6FrameDecoder.java | 32 +++ .../java/org/traccar/protocol/NDTPv6Protocol.java | 26 ++ .../traccar/protocol/NDTPv6ProtocolDecoder.java | 309 +++++++++++++++++++++ .../traccar/protocol/NDTPv6ProtocolEncoder.java | 38 +++ 5 files changed, 406 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/NDTPv6FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NDTPv6Protocol.java create mode 100644 src/main/java/org/traccar/protocol/NDTPv6ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NDTPv6ProtocolEncoder.java diff --git a/setup/default.xml b/setup/default.xml index 607efc35f..4f1e3ca30 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -284,5 +284,6 @@ 5239 5240 5241 + 5242 diff --git a/src/main/java/org/traccar/protocol/NDTPv6FrameDecoder.java b/src/main/java/org/traccar/protocol/NDTPv6FrameDecoder.java new file mode 100644 index 000000000..c869b11a4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NDTPv6FrameDecoder.java @@ -0,0 +1,32 @@ +/* + * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class NDTPv6FrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + return buf; + } + +} diff --git a/src/main/java/org/traccar/protocol/NDTPv6Protocol.java b/src/main/java/org/traccar/protocol/NDTPv6Protocol.java new file mode 100644 index 000000000..78dc11b50 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NDTPv6Protocol.java @@ -0,0 +1,26 @@ +/* + * 2020 - NDTP v6 Protocol + */ +package org.traccar.protocol; + +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +import javax.inject.Inject; + +public class NDTPv6Protocol extends BaseProtocol { + + @Inject + public NDTPv6Protocol(Config config) { + addServer( + new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new NDTPv6ProtocolDecoder(NDTPv6Protocol.this)); + } + } + ); + } +} diff --git a/src/main/java/org/traccar/protocol/NDTPv6ProtocolDecoder.java b/src/main/java/org/traccar/protocol/NDTPv6ProtocolDecoder.java new file mode 100644 index 000000000..788afd65b --- /dev/null +++ b/src/main/java/org/traccar/protocol/NDTPv6ProtocolDecoder.java @@ -0,0 +1,309 @@ +/* + * 2020 - NDTP v6 Protocol Decoder + */ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; + +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Date; + +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.model.Position; +import org.traccar.session.DeviceSession; + +public class NDTPv6ProtocolDecoder extends BaseProtocolDecoder { + + public NDTPv6ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final byte[] SIGNATURE = {0x7E, 0x7E}; + + private static final int NPL_FLAG_CRC = 2; + private static final int NPH_RESULT_OK = 0x00000000; + private static final int NPL_TYPE_NPH = 2; + private static final int NPL_ADDRESS_SERVER = 0; + + /* common packets for all services */ + private static final int NPH_RESULT = 0; + + /* NPH service types */ + private static final int NPH_SRV_GENERIC_CONTROLS = 0; + private static final int NPH_SRV_NAVDATA = 1; + + /* NPH_SRV_GENERIC_CONTROLS packets */ + private static final int NPH_SGC_RESULT = NPH_RESULT; + private static final int NPH_SGC_CONN_REQUEST = 100; + + /* NPH_SRV_NAVDATA packets */ + private static final int NPH_SND_RESULT = NPH_RESULT; + + private static void sendResultResponse( + Channel channel, + short serviceId, + int requestId, + int nphSendResult, + int nphResult + ) { + // Формирование пакета данных + byte[] serviceIdBytes = ByteBuffer + .allocate(2) + .order(ByteOrder.LITTLE_ENDIAN) + .putShort(serviceId) + .array(); + byte[] nphSendResultBytes = ByteBuffer + .allocate(4) + .order(ByteOrder.LITTLE_ENDIAN) + .putInt(nphSendResult) + .array(); + byte[] requestIdBytes = ByteBuffer + .allocate(4) + .order(ByteOrder.LITTLE_ENDIAN) + .putInt(requestId) + .array(); + byte[] nphResultBytes = ByteBuffer + .allocate(4) + .order(ByteOrder.LITTLE_ENDIAN) + .putInt(nphResult) + .array(); + + byte[] allByteArray = new byte[serviceIdBytes.length + + requestIdBytes.length + + nphSendResultBytes.length + + nphResultBytes.length]; + + System.arraycopy(serviceIdBytes, 0, allByteArray, 0, serviceIdBytes.length); + System.arraycopy( + nphSendResultBytes, + 0, + allByteArray, + serviceIdBytes.length, + nphSendResultBytes.length + ); + System.arraycopy( + requestIdBytes, + 0, + allByteArray, + serviceIdBytes.length + nphSendResultBytes.length, + requestIdBytes.length + ); + System.arraycopy( + nphResultBytes, + 0, + allByteArray, + serviceIdBytes.length + requestIdBytes.length + nphSendResultBytes.length, + nphResultBytes.length + ); + + // ПАКЕТ ОТВЕТА КЛИЕНТУ + ByteBuf response = Unpooled.buffer(); + // NPL + response.writeBytes(SIGNATURE); + response.writeShortLE(allByteArray.length); // Размер данных + response.writeShortLE(NPL_FLAG_CRC); // Флаги + + response.writeShort( + Checksum.crc16(Checksum.CRC16_MODBUS, ByteBuffer.wrap(allByteArray)) + ); // CRC + response.writeByte(NPL_TYPE_NPH); // Тип + response.writeIntLE(NPL_ADDRESS_SERVER); // peer_address + response.writeShortLE(0); // request_id + + response.writeBytes(allByteArray); + + channel.writeAndFlush( + new NetworkMessage(response, channel.remoteAddress()) + ); + } + + private static final short MAIN_NAV_DATA = 0; + private static final short ADDITIONAL_NAV_DATA = 2; + + private void decodeData(ByteBuf buf, Position position, int dataType) { + if (dataType == NPH_SRV_NAVDATA) { + short cellType; + short cellNumber; + + cellType = buf.readUnsignedByte(); // Тип ячейки + cellNumber = buf.readUnsignedByte(); // Номер ячейки + if (cellType == MAIN_NAV_DATA && (cellNumber == 0 || cellNumber == 1)) { + position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); // Значение реального времени unix + position.setLongitude(buf.readIntLE() / 10000000.0); // Долгота в градусах, умноженная на 10 000 000 + position.setLatitude(buf.readIntLE() / 10000000.0); // Широта в градусах, умноженная на 10 000 000 + + short flags = buf.readUnsignedByte(); // Достоверность навигационных данных: + // bit7 - достоверность нав. данных (1 - достоверны, 0 – нет); + // bit6 - полушарие долготы (1 – E, 0 – W); + // bit5 - полушарие широты (1 – N, 0 – S); + // bit4 - флаг работы от встроенного аккумулятора; + // bit3 – флаг первоначального включения; + // bit2 – состояние SOS (1 – SOS, 0 – нет SOS); + // bit1 – флаг тревожной информации (один из параметров + // находится в диапазоне тревоги) + position.setValid(BitUtil.check(flags, 7)); + if (BitUtil.check(flags, 1)) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 20); // Напряжение батареи, 1бит = 20мВ + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShortLE()); // Средняя скорость за период в км/ч + position.setSpeed(buf.readUnsignedShortLE() / 1.85); // Максимальная скорость за период в км/ч + + int course = buf.readUnsignedShortLE(); // Направление движения + position.setCourse(course); + + position.set(Position.KEY_DISTANCE, buf.readUnsignedShortLE()); // Пройденный путь, м + position.setAltitude(buf.readShortLE()); // Высота над уровнем моря в метрах (-18000 - +18000) + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); // Количество видимых спутников + position.set(Position.KEY_PDOP, buf.readUnsignedByte()); // PDOP + } + cellType = buf.readUnsignedByte(); // Тип ячейки + cellNumber = buf.readUnsignedByte(); // Номер ячейки + if (cellType == ADDITIONAL_NAV_DATA && cellNumber == 0) { + int analogIn1 = buf.readUnsignedShortLE(); // Значение 0 аналогового входа в 16 битном формате + //(analogIn1 - отражает напряжение на батерии для радиоборта) + int analogIn2 = buf.readUnsignedShortLE(); // Значение 1 аналогового входа в 16 битном формате + int analogIn3 = buf.readUnsignedShortLE(); // Значение 2 аналогового входа в 16 битном формате + int analogIn4 = buf.readUnsignedShortLE(); // Значение 3 аналогового входа в 16 битном формате + + buf.readUnsignedByte(); // Значение цифровых входов + buf.readUnsignedByte(); // Состояние дискретных выходов + buf.readUnsignedShortLE(); // Количество импульсов на дискретном входе 0 с предыдущей нав. отметки + buf.readUnsignedShortLE(); // Количество импульсов на дискретном входе 1 с предыдущей нав. отметки + buf.readUnsignedShortLE(); // Количество импульсов на дискретном входе 2 с предыдущей нав. отметки + buf.readUnsignedShortLE(); // Количество импульсов на дискретном входе 3 с предыдущей нав. отметки + buf.readUnsignedIntLE(); // Длина трека с момента первого включения + + position.set(Position.KEY_ANTENNA, buf.readUnsignedByte()); // Сила GSM сигнала + position.set(Position.KEY_GPS, buf.readUnsignedByte()); // Состояние GPRS подключения + position.set(Position.KEY_ACCELERATION, buf.readUnsignedByte()); // Акселерометр - энергия + position.set(Position.KEY_POWER, buf.readUnsignedByte() * 200); // Напряжение борт. сети (1бит - 200мв) + + position.set(Position.PREFIX_ADC + 1, analogIn1 * 1); + position.set(Position.PREFIX_ADC + 2, analogIn2 * 1); + position.set(Position.PREFIX_ADC + 3, analogIn3 * 1); + position.set(Position.PREFIX_ADC + 4, analogIn4 * 1); + + // Расчет уровня батареи + // float Voltage = 5 / 4096 * analogIn1; // Вольтаж + + float batteryLevel = (analogIn1 - 3600) / 6; + + if (batteryLevel > 100) { + batteryLevel = 100; + } + if (batteryLevel < 0) { + batteryLevel = 0; + } + + position.set(Position.KEY_BATTERY_LEVEL, batteryLevel); + } + } + } + + @Override + protected Object decode( + Channel channel, + SocketAddress remoteAddress, + Object msg + ) + throws Exception { + ByteBuf buf = (ByteBuf) msg; + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + + // Заголовок NPL + buf.skipBytes(2); // Сигнатура (7e 7e) + buf.readUnsignedShortLE(); // Размер данных (nph + размер массива данных) + buf.readUnsignedShortLE(); // Флаги соединения (2 - проверять crc) + buf.readUnsignedShortLE(); // CRC (Modbus) + buf.readUnsignedByte(); // Тип пакета (nph) + buf.readUnsignedIntLE(); // Адрес участника соединения + buf.readUnsignedShortLE(); // Идентификатор NPL + + // Заголовок NPH + int serviceId = buf.readUnsignedShortLE(); // Идентификатор услуги (NPH_SRV_NAVDATA) service_id + int serviceType = buf.readUnsignedShortLE(); // Тип пакета + buf.readUnsignedShortLE(); // Флаг (1 - требуется подтверждение) NPH_FLAG_REQUEST + long requestId = buf.readUnsignedIntLE(); // Идентификатор nph + + if ( + deviceSession == null && + serviceId == NPH_SRV_GENERIC_CONTROLS && + serviceType == NPH_SGC_CONN_REQUEST + ) { // Регистрация устройства + buf.readUnsignedShortLE(); // Версия протокола NDTP (старший номер) + buf.readUnsignedShortLE(); // Версия протокола NDTP (младший номер) + buf.readUnsignedShortLE(); // Опции соединения (connection_flags) + // Определяет настройки соединения, + // которые будут использоваться после установки соединения. + // На данный момент их две: + // - бит0: шифровать пакеты (0 - нет, 1 — да) + // - бит1: рассчитывать CRC пакетов (0 - нет, 1 — да) + // - бит2: подключение симулятора (0 — подключается обычный клиент, + // 1 подключается симулятор) + // - бит3: тип алгоритма шифрования. + // - 0 - blowfish + // - 1 – ГОСТ + // - бит8: наличие поля IMEI (0 - нет, 1 — да) + // - бит9: наличие поля IMSI (0 - нет, 1 — да) + // - остальные биты не используются. + int deviceId = buf.readUnsignedShortLE(); + Position position = new Position(getProtocolName()); + deviceSession = + getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); + position.setDeviceId(deviceSession.getDeviceId()); + + if (channel != null) { + sendResultResponse( + channel, + (short) serviceId, + (int) requestId, + NPH_SND_RESULT, + NPH_RESULT_OK + ); + } + + position.set(Position.KEY_RESULT, String.valueOf(NPH_SGC_RESULT)); + position.setTime(new Date()); + getLastLocation(position, new Date()); + position.setValid(false); + + return position; + } + + if (serviceId == NPH_SRV_NAVDATA) { + deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (channel != null) { + sendResultResponse( + channel, + (short) serviceId, + (int) requestId, + NPH_SND_RESULT, + NPH_RESULT_OK + ); + } + + decodeData(buf, position, NPH_SRV_NAVDATA); + + return position; + } + + return null; + } +} diff --git a/src/main/java/org/traccar/protocol/NDTPv6ProtocolEncoder.java b/src/main/java/org/traccar/protocol/NDTPv6ProtocolEncoder.java new file mode 100644 index 000000000..af0dd58f9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NDTPv6ProtocolEncoder.java @@ -0,0 +1,38 @@ +/* + * 2020 - NDTP v6 Protocol Encoder + */ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import java.nio.charset.StandardCharsets; +import org.traccar.BaseProtocolEncoder; +import org.traccar.Protocol; +import org.traccar.model.Command; + +public class NDTPv6ProtocolEncoder extends BaseProtocolEncoder { + + public NDTPv6ProtocolEncoder(Protocol protocol) { + super(protocol); + } + + private ByteBuf encodeCommand(String commandString) { + ByteBuf buffer = Unpooled.buffer(); + buffer.writeBytes(commandString.getBytes(StandardCharsets.US_ASCII)); + return buffer; + } + + @Override + protected Object encodeCommand(Command command) { + switch (command.getType()) { + case Command.TYPE_IDENTIFICATION: + return encodeCommand("BB+IDNT"); + case Command.TYPE_REBOOT_DEVICE: + return encodeCommand("BB+RESET"); + case Command.TYPE_POSITION_SINGLE: + return encodeCommand("BB+RRCD"); + default: + return null; + } + } +} -- cgit v1.2.3 From 596f755e19ec38cf5ce426595e2fba1a5b156338 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 8 Sep 2022 06:15:12 -0700 Subject: Attributes never null --- src/main/java/org/traccar/model/ExtendedModel.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/model/ExtendedModel.java b/src/main/java/org/traccar/model/ExtendedModel.java index 0fa1856d1..ef2e3b68f 100644 --- a/src/main/java/org/traccar/model/ExtendedModel.java +++ b/src/main/java/org/traccar/model/ExtendedModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.traccar.model; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; public class ExtendedModel extends BaseModel { @@ -31,7 +32,7 @@ public class ExtendedModel extends BaseModel { } public void setAttributes(Map attributes) { - this.attributes = attributes; + this.attributes = Objects.requireNonNullElseGet(attributes, LinkedHashMap::new); } public void set(String key, Boolean value) { -- cgit v1.2.3 From 3ac73dabfd5d9fb403c119574acd1581daa12b90 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 8 Sep 2022 06:44:45 -0700 Subject: Add Thuraya protocol support --- setup/default.xml | 1 + .../java/org/traccar/protocol/ThurayaProtocol.java | 39 +++++ .../traccar/protocol/ThurayaProtocolDecoder.java | 195 +++++++++++++++++++++ .../protocol/ThurayaProtocolDecoderTest.java | 24 +++ 4 files changed, 259 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/ThurayaProtocol.java create mode 100644 src/main/java/org/traccar/protocol/ThurayaProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java diff --git a/setup/default.xml b/setup/default.xml index 607efc35f..b1417bd95 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -284,5 +284,6 @@ 5239 5240 5241 + 5242 diff --git a/src/main/java/org/traccar/protocol/ThurayaProtocol.java b/src/main/java/org/traccar/protocol/ThurayaProtocol.java new file mode 100644 index 000000000..f709a1183 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ThurayaProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2022 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 javax.inject.Inject; + +public class ThurayaProtocol extends BaseProtocol { + + @Inject + public ThurayaProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0)); + pipeline.addLast(new ThurayaProtocolDecoder(ThurayaProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/ThurayaProtocolDecoder.java b/src/main/java/org/traccar/protocol/ThurayaProtocolDecoder.java new file mode 100644 index 000000000..a287ece34 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ThurayaProtocolDecoder.java @@ -0,0 +1,195 @@ +/* + * Copyright 2022 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.DateBuilder; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; + +public class ThurayaProtocolDecoder extends BaseProtocolDecoder { + + public ThurayaProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_EVENT = 0x5101; + public static final int MSG_PERIODIC_REPORT = 0x7101; + public static final int MSG_SETTING_RESPONSE = 0x8115; + public static final int MSG_ACK = 0x9901; + + private static int checksum(ByteBuffer buf) { + int crc = 0; + while (buf.hasRemaining()) { + crc += buf.get(); + } + crc = ~crc; + crc += 1; + return crc; + } + + private void sendResponse(Channel channel, SocketAddress remoteAddress, long id, int type) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeCharSequence("#T", StandardCharsets.US_ASCII); + response.writeShort(15); // length + response.writeShort(MSG_ACK); + response.writeInt((int) id); + response.writeShort(type); + response.writeShort(1); // server ok + response.writeShort(checksum(response.nioBuffer())); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + private void decodeLocation(ByteBuf buf, Position position) { + + position.setValid(true); + + DateBuilder dateBuilder = new DateBuilder(); + + int date = buf.readInt(); + dateBuilder.setDay(date % 100); + date /= 100; + dateBuilder.setMonth(date % 100); + date /= 100; + dateBuilder.setYear(date); + + int time = buf.readInt(); + dateBuilder.setSecond(time % 100); + time /= 100; + dateBuilder.setMinute(time % 100); + time /= 100; + dateBuilder.setHour(time); + + position.setTime(dateBuilder.getDate()); + + position.setLongitude(buf.readInt() / 1000000.0); + position.setLatitude(buf.readInt() / 1000000.0); + + int data = buf.readUnsignedShort(); + + int ignition = BitUtil.from(data, 12); + if (ignition == 1) { + position.set(Position.KEY_IGNITION, true); + } else if (ignition == 2) { + position.set(Position.KEY_IGNITION, false); + } + + position.setCourse(BitUtil.to(data, 12)); + position.setSpeed(buf.readShort()); + + position.set(Position.KEY_RPM, buf.readShort()); + + position.set("data", readString(buf)); + } + + private String decodeAlarm(int event) { + switch (event) { + case 10: + return Position.ALARM_VIBRATION; + case 11: + return Position.ALARM_OVERSPEED; + case 12: + return Position.ALARM_POWER_CUT; + case 13: + return Position.ALARM_LOW_BATTERY; + case 18: + return Position.ALARM_GPS_ANTENNA_CUT; + case 20: + return Position.ALARM_ACCELERATION; + case 21: + return Position.ALARM_BRAKING; + default: + return null; + } + } + + private String readString(ByteBuf buf) { + int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0); + CharSequence value = buf.readCharSequence(endIndex - buf.readerIndex(), StandardCharsets.US_ASCII); + buf.readUnsignedByte(); // delimiter + return value.toString(); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // service + buf.readUnsignedShort(); // length + int type = buf.readUnsignedShort(); + long id = buf.readUnsignedInt(); + + sendResponse(channel, remoteAddress, id, type); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); + if (deviceSession == null) { + return null; + } + + if (type == MSG_EVENT) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + decodeLocation(buf, position); + + int event = buf.readUnsignedByte(); + position.set(Position.KEY_ALARM, decodeAlarm(event)); + position.set(Position.KEY_EVENT, event); + position.set("eventData", readString(buf)); + + return position; + + } else if (type == MSG_PERIODIC_REPORT) { + + List positions = new LinkedList<>(); + + int count = buf.readUnsignedByte(); + for (int i = 0; i < count; i++) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + decodeLocation(buf, position); + + positions.add(position); + + } + + return positions; + + } + + return null; + } + +} diff --git a/src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java new file mode 100644 index 000000000..90431fa24 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ThurayaProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = inject(new ThurayaProtocolDecoder(null)); + + verifyPositions(decoder, binary( + "235400437101072bca3c0201348b9a00014c9f085493fc02200c5411470000000042323a300001348b9a00014d03085493ea02200c5010000000000042323a3000f2c1")); + + verifyPosition(decoder, binary( + "2354002b5101072bca3c01348b9a00013fba000000000000000010000000000042323a3000174f4e00f9de")); + + verifyNull(decoder, binary( + "235400d88115071e37d691030133342e3233362e3133302e3637000000001e56313030320030000700080102030405060708020101010101020201030103030302020000007800000078000004b000001c20050a64000015b3800015b374657374696e67003132333435360002010f28393031303539383938303134373738000043383a592c43373a592c43333a592c43323a592c43313a592c42353a592c42343a592c42323a592c42313a592c41323a592c41313a590045313a592c45373a590065746973616c61742e61650047455400322e3130d6de")); + + } + +} -- cgit v1.2.3 From 9b5654e253ed3dedfb43125a0611896dfa8fc863 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 8 Sep 2022 08:03:04 -0700 Subject: Handle unlinked notifications --- src/main/java/org/traccar/session/cache/CacheManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index 6f6b648fa..64397b368 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -132,7 +132,7 @@ public class CacheManager implements BroadcastInterface { lock.readLock().lock(); var users = deviceLinks.get(deviceId).get(User.class).stream() .collect(Collectors.toUnmodifiableSet()); - return notificationUsers.get(notificationId).stream() + return notificationUsers.getOrDefault(notificationId, new LinkedList<>()).stream() .filter(user -> users.contains(user.getId())) .collect(Collectors.toUnmodifiableList()); } finally { -- cgit v1.2.3 From ff95c7dc0adf17710438f7dd2168d6ad1dd31415 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 9 Sep 2022 16:59:54 -0700 Subject: Decode G18 light sensor --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 5 +++-- src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index b65e4a4b8..885ea4bab 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -411,9 +411,12 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { case 0x11: return Position.ALARM_POWER_OFF; case 0x13: + case 0x25: return Position.ALARM_TAMPERING; case 0x14: return Position.ALARM_DOOR; + case 0x23: + return Position.ALARM_FALL_DOWN; case 0x29: return Position.ALARM_ACCELERATION; case 0x30: @@ -423,8 +426,6 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { return Position.ALARM_CORNERING; case 0x2C: return Position.ALARM_ACCIDENT; - case 0x23: - return Position.ALARM_FALL_DOWN; default: return null; } diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index f3f47a104..6ab78260c 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttribute(decoder, binary( + "78782516160908063736c0006e70110442fc800000000800000000000000000300002512000473fb0d0a"), + Position.KEY_ALARM, Position.ALARM_TAMPERING); + verifyPosition(decoder, binary( "78782e2416061a103600c80275298404a0a24000184602d4023a49006f060104ed01940000086508004139765000be7d640d0a")); -- cgit v1.2.3 From 725195a271f4313255b80c99278b3a91cff799e1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 9 Sep 2022 17:35:56 -0700 Subject: Add DT700 bluetooth temperature --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 10 ++++++++++ .../java/org/traccar/protocol/HuabaoProtocolDecoderTest.java | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 5393c6f74..d2b8f1fb5 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -513,6 +513,16 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_MOTION, BitUtil.check(deviceStatus, 2)); position.set("cover", BitUtil.check(deviceStatus, 3)); break; + case 0xE6: + int sensorIndex = buf.readUnsignedByte(); + buf.skipBytes(6); // mac + position.set( + Position.PREFIX_TEMP + sensorIndex, + buf.readUnsignedByte() + buf.readUnsignedByte() * 0.01); + position.set( + "humidity" + sensorIndex, + buf.readUnsignedByte() + buf.readUnsignedByte() * 0.01); + break; case 0xEB: if (buf.getUnsignedShort(buf.readerIndex()) > 200) { Network network = new Network(); diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 7322185d5..4ef2e25ea 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { var decoder = inject(new HuabaoProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "7e0200003d012291302256004800000000000c012300d2648805ff31db000e0000000022090708255503020000a70400000000ac04000002bce5020000e60b01dd34020754fe1bce3efc357e"), + Position.PREFIX_TEMP + 1, 29.06); + verifyAttribute(decoder, binary( "7E0200008201215233475100030000000000000003015A7F6106CF8CEC003D0000000021071311481901040000005630011931011AE10200755D3D0601CC0024990A7dA0032301CC002499099B2941FC01CC002499099B29430B01CC0024990A7dA0290601CC0024990A7dA015FD01CC0026220994506BFFFE157C010400000001F10C000000000000000000000000997E"), Position.KEY_ALARM, Position.ALARM_ACCELERATION); -- cgit v1.2.3 From 18807d840ce04f8052f4b1fc842f4ad2da958326 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 10 Sep 2022 16:37:53 -0700 Subject: Fix GT800 door decoding --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 7 +++++++ src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 885ea4bab..7eeee5efb 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -987,6 +987,13 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } else if (subType == 0x05) { + if (buf.readableBytes() >= 6 + 1 + 6) { + DateBuilder dateBuilder = new DateBuilder((TimeZone) deviceSession.get(DeviceSession.KEY_TIMEZONE)) + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setDeviceTime(dateBuilder.getDate()); + } + int flags = buf.readUnsignedByte(); position.set(Position.KEY_DOOR, BitUtil.check(flags, 0)); position.set(Position.PREFIX_IO + 1, BitUtil.check(flags, 2)); diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 6ab78260c..1570dcf32 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,10 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttribute(decoder, binary( + "7979000d940516090908081c030defbd2d0d0a"), + Position.KEY_DOOR, true); + verifyAttribute(decoder, binary( "78782516160908063736c0006e70110442fc800000000800000000000000000300002512000473fb0d0a"), Position.KEY_ALARM, Position.ALARM_TAMPERING); -- cgit v1.2.3 From 1ea1c4be35687a505e21ede7b2c1e611c52f5e4a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 11 Sep 2022 15:13:55 -0700 Subject: Add Meitrack T711L test --- src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java index 09ab0440d..0fc51b8b6 100644 --- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest { var decoder = inject(new MeitrackProtocolDecoder(null)); + verifyPositions(decoder, binary( + "2424423233322c3836323039303035303030323831332c4343452c0400000003004400110004050006000700fe6962060800000900000a00000b00001aef044023000602d65fbcfd03173b9c0804cc76ae2a0c14ae1b000d00aa0d001c01000000014b030101003f00100004050006000700fe695f060800000900000a00000b00001aea044016000502d65fbcfd03173b9c0804cf76ae2a0c14ae1b000d03aa0d00014b030101003f00100004050006000700fe695f060800000900000a00000b00001aed044001000502d65fbcfd03173b9c0804d076ae2a0c14ae1b000d04aa0d00014b030101002a30460d0a")); + verifyAttribute(decoder, buffer( "$$F160,861412043027965,AAA,22,45.499458,-82.493581,220718171428,V,0,0,0,0,0.0,0,227940,119812,302|220|D8D6|086E1B2B,0000,0000|0000|0000|0191|0573,,,3,,002134,0,0*FA"), Position.KEY_POWER, 13.95); -- cgit v1.2.3 From b51526fdb177d3641e2780d5485586b487850874 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 11 Sep 2022 17:44:49 -0700 Subject: Fix column name --- schema/changelog-5.2.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema/changelog-5.2.xml b/schema/changelog-5.2.xml index 1ac9eedc5..687024f52 100644 --- a/schema/changelog-5.2.xml +++ b/schema/changelog-5.2.xml @@ -13,7 +13,7 @@ - + -- cgit v1.2.3 From 251829fb7583c50c0bac97bc47d41bdbf63cf6c1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 12 Sep 2022 06:01:02 -0700 Subject: Fix manager permission check --- src/main/java/org/traccar/api/security/PermissionsService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index a494c0257..ddfaaab94 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -170,8 +170,10 @@ public class PermissionsService { || before.getFixedEmail() != after.getFixedEmail()) { if (userId == after.getId()) { checkAdmin(userId); - } else { + } else if (after.getId() > 0) { checkUser(userId, after.getId()); + } else { + checkManager(userId); } } if (before.getFixedEmail() && !before.getEmail().equals(after.getEmail())) { -- cgit v1.2.3 From 30e04d7209561b7ebf6055a9170794ab9496c357 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 13 Sep 2022 06:50:44 -0700 Subject: Fix PostgreSQL blob (fix #4947) --- schema/changelog-5.3.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/schema/changelog-5.3.xml b/schema/changelog-5.3.xml index 2021fe6c7..1e5a6005a 100644 --- a/schema/changelog-5.3.xml +++ b/schema/changelog-5.3.xml @@ -24,10 +24,10 @@ - + - + -- cgit v1.2.3 From 73407e12acce8061cc1aa3d18517569368707864 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 16 Sep 2022 17:55:45 -0700 Subject: Safer Teltonika IO decoding --- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 5 ++++- src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 89124cb22..ff1f52eb1 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -325,6 +325,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { if (codec == CODEC_GH3000) { decodeGh3000Parameter(position, id, buf, length); } else { + int index = buf.readerIndex(); boolean decoded = false; for (var entry : PARAMETERS.getOrDefault(id, new HashMap<>()).entrySet()) { if (entry.getKey() == null || model != null && entry.getKey().contains(model)) { @@ -333,7 +334,9 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { break; } } - if (!decoded) { + if (decoded) { + buf.readerIndex(index + length); + } else { position.set(Position.PREFIX_IO + id, readValue(buf, length)); } } diff --git a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java index 994a55109..197391d7f 100644 --- a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java @@ -14,6 +14,9 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "000F313233343536373839303132333435")); + verifyPositions(decoder, binary( + "00000000000004258e0400000182a701b49301d5d90ab7ebe4aae101be003d12000000f7003d000e00f70100ef0000f00000500500150200c800004501000100001d00001400001600001700007157010701001d00b5000b00b60006004230400018000000cd223f00ce741700430f8900440000000d00010011ffe50012001f0013ffce000f03e800190bb8001a0bb8001b0bb8001c0bb800560bb800680bb8006a0bb8006c0bb8010e0000011100000114000001170000014f0000015000000151000001520000000a00f100011d2a00c700000000001000b9addc000c0000acb600040000000001320000000001330000000001340000000001350000000001c1000000000003000b000000d14675f36000ee0000000000000000000e0000000003fd509f0005014b0000014c0000014d0000014e0000018300222d3333373333382e0100000053a6fb624588040001ba86064f0eae51c0fdaf4d3de500000182a701b82001d5d90ab7ebe4aae101be003d12000000f0003c000d00ef0000f00100500500150200c800004501000100001d00001400001600001700007152010701001d00b5000900b60006004217e50018000000cd223f00ce741700430f5c00440000000d00010011fed60012fd1d0013f1f2000f03e800190bb8001a0bb8001b0bb8001c0bb800560bb800680bb8006a0bb8006c0bb8010e0000011100000114000001170000014f0000015000000151000001520000000a00f100011d2a00c700000000001000b9addc000c0000acb600040000000001320000000001330000000001340000000001350000000001c1000000000003000b000000d14675f36000ee0000000000000000000e0000000003fd509f0005014b0000014c0000014d0000014e0000018300222d3333373333352e353833332d303730373139362e323333332b3030302e3434362f00000182a701bc0801d5d90ab7ebe4aae101be003d12000000fc003d000e00ef0000f00100500500150200c800004501000100001d0000140000160000170000714d01070100fc01001d00b5000900b60006004217e50018000000cd223f00ce741700430f5c00440000000d00010011fed60012fd1d0013f1f2000f03e800190bb8001a0bb8001b0bb8001c0bb800560bb800680bb8006a0bb8006c0bb8010e0000011100000114000001170000014f0000015000000151000001520000000a00f100011d2a00c700000000001000b9addc000c0000acb600040000000001320000000001330000000001340000000001350000000001c1000000000003000b000000d14675f36000ee0000000000000000000e0000000003fd509f0005014b0000014c0000014d0000014e0000018300222d3333373333352e353833332d303730373139362e323333332b3030302e3434362f00000182a7018d8d01d5d8ffa6ebe4a0ca01be006111000000f70001000100f70500000000000000000400003a10")); + verifyPositions(decoder, binary( "00000000000003831004000001735ace37f80000e3b9331c71e290006900e211005100fd072e1600010100160300470300f00100150400b20000c80000ef01009000004f00005101005201005300005538006e00006f00007a03007d00007f5600890000fd0200fe1f09004326b00044000000b5000b00b6000600427029001800540046015d00ce4ec10080000f0f00f10000515400cd007404ab00d80f5022a1005000000054005400000000005600015568005700000060005800000420006800001113006d303330300071fffd8c85008700000020008800000002008a000155f5008b0000b86000000001735ace3ca80000e3b08a1c71dd29006900e311005100fd072e1600010100160300470300f00100150400b20000c80000ef01009000004f00005101005201005300005537006e00006f00007a03007d00007f5600890000fd0200fe1d09004326ac0044000000b5000b00b600060042701f001800540046015d00ce4ec10080000f0f00f10000515400cd007404ab00d80f5022ce00500000005400540000000000560001556800570000006000580000041f006800001113006d303330300071fffd8c85008700000020008800000002008a000155f5008b0000b86000000001735ace3fc80000e3a7c01c71d7c2006900e311005100fd072e1600010100160300470300f00100150400b20000c80000ef01009000004f00005101005201005300005537006e00006f00007a03007d00007f5600890000fd0200fe2309004326ac0044000000b5000b00b6000600427015001800540046015e00ce4ec10080000f0f00f10000515400cd007404ab00d80f5022e700500000005400540000000000560001556800570000006000580000041f006800001113006d303330300071fffd8c85008700000020008800000002008a000155f5008b0000b86000000001735ace3ffa0000e3a7c01c71d7c2006900e311005100fd072e1600010100160300470300f00100150400b20000c80000ef01009000004f00005101005201005300005537006e00006f00007a03007d00007f5600890000fd0300fe2309004326ac0044000000b5000b00b6000600427015001800540046015e00ce4ec10080000f0f00f10000515400cd007404ab00d80f5022e700500000005400540000000000560001556800570000006000580000041f006800001113006d303330300071fffd8c85008700000020008800000002008a000155f5008b0000b86000040000eb85")); -- cgit v1.2.3 From 729bf987349dc9230293140139dd8ad10b7de107 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 16 Sep 2022 18:17:28 -0700 Subject: Handle multiple DT700 sensors --- .../org/traccar/protocol/HuabaoProtocolDecoder.java | 18 ++++++++++-------- .../traccar/protocol/HuabaoProtocolDecoderTest.java | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index d2b8f1fb5..0639b9dcf 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -514,14 +514,16 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set("cover", BitUtil.check(deviceStatus, 3)); break; case 0xE6: - int sensorIndex = buf.readUnsignedByte(); - buf.skipBytes(6); // mac - position.set( - Position.PREFIX_TEMP + sensorIndex, - buf.readUnsignedByte() + buf.readUnsignedByte() * 0.01); - position.set( - "humidity" + sensorIndex, - buf.readUnsignedByte() + buf.readUnsignedByte() * 0.01); + while (buf.readerIndex() < endIndex) { + int sensorIndex = buf.readUnsignedByte(); + buf.skipBytes(6); // mac + position.set( + Position.PREFIX_TEMP + sensorIndex, + buf.readUnsignedByte() + buf.readUnsignedByte() * 0.01); + position.set( + "humidity" + sensorIndex, + buf.readUnsignedByte() + buf.readUnsignedByte() * 0.01); + } break; case 0xEB: if (buf.getUnsignedShort(buf.readerIndex()) > 200) { diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 4ef2e25ea..3661a0202 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -12,8 +12,8 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { var decoder = inject(new HuabaoProtocolDecoder(null)); verifyAttribute(decoder, binary( - "7e0200003d012291302256004800000000000c012300d2648805ff31db000e0000000022090708255503020000a70400000000ac04000002bce5020000e60b01dd34020754fe1bce3efc357e"), - Position.PREFIX_TEMP + 1, 29.06); + "7e0200005e01229130231209e300000000000c002300d264a305ff322300160000000022091514493503020000a70400000000ac0400000000e5020003e62c01bc5729009ca319bbff0002dd34020754fe1a83393c03bc572900ce371a6133d704dd34020751551d00fefb9a7e"), + Position.PREFIX_TEMP + 4, 29.0); verifyAttribute(decoder, binary( "7E0200008201215233475100030000000000000003015A7F6106CF8CEC003D0000000021071311481901040000005630011931011AE10200755D3D0601CC0024990A7dA0032301CC002499099B2941FC01CC002499099B29430B01CC0024990A7dA0290601CC0024990A7dA015FD01CC0026220994506BFFFE157C010400000001F10C000000000000000000000000997E"), -- cgit v1.2.3 From fd2e2183bb34951e5e9248b77e93b2e4abf1c94e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 16 Sep 2022 18:29:28 -0700 Subject: Add Fifotrack Q2 response --- .../traccar/protocol/FifotrackProtocolDecoder.java | 26 +++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java index 741f4b35a..a9d77b46e 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -34,6 +34,10 @@ import org.traccar.model.WifiAccessPoint; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; import java.util.regex.Pattern; public class FifotrackProtocolDecoder extends BaseProtocolDecoder { @@ -78,7 +82,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { .text("$$") .number("d+,") // length .number("(d+),") // imei - .number("x+,") // index + .number("(x+),") // index .text("A03,") // type .number("(d+)?,") // alarm .number("(dd)(dd)(dd)") // date (yymmdd) @@ -137,16 +141,20 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { .number("xx") .compile(); - private void requestPhoto(Channel channel, SocketAddress socketAddress, String imei, String file) { + private void sendResponse(Channel channel, SocketAddress remoteAddress, String imei, String content) { if (channel != null) { - String content = "1,D06," + file + "," + photo.writerIndex() + "," + Math.min(1024, photo.writableBytes()); int length = 1 + imei.length() + 1 + content.length(); String response = String.format("##%02d,%s,%s*", length, imei, content); response += Checksum.sum(response) + "\r\n"; - channel.writeAndFlush(new NetworkMessage(response, socketAddress)); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } } + private void requestPhoto(Channel channel, SocketAddress remoteAddress, String imei, String file) { + String content = "1,D06," + file + "," + photo.writerIndex() + "," + Math.min(1024, photo.writableBytes()); + sendResponse(channel, remoteAddress, imei, content); + } + private String decodeAlarm(Integer alarm) { if (alarm != null) { switch (alarm) { @@ -200,11 +208,14 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { return null; } - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + String imei = parser.next(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); if (deviceSession == null) { return null; } + String index = parser.next(); + Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); @@ -243,6 +254,11 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { position.setNetwork(network); + DateFormat dateFormat = new SimpleDateFormat("yyMMddHHmmss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + String response = index + ",A03," + dateFormat.format(new Date()); + sendResponse(channel, remoteAddress, imei, response); + return position; } -- cgit v1.2.3 From 79ecdf701ce5db5505c366bafe4f04e4d565ec7d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 17 Sep 2022 16:57:29 -0700 Subject: Fix temperature decoding --- src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 9122eb362..eb8c1c466 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 2022 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. @@ -293,7 +293,9 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 51: case 52: value = buf.readByte(); - position.set(Position.PREFIX_TEMP + (j + 2 - 45), (value != 0x80) ? value : null); + position.set( + Position.PREFIX_TEMP + (j + 2 - 45), + (value != (byte) 0x80) ? value : null); break; default: buf.skipBytes(getItemLength(j + 1)); -- cgit v1.2.3 From 3a6219d8cc2a014a78d53f9ca9695558ffd72926 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 17 Sep 2022 16:58:10 -0700 Subject: Remove unnecessary assignment --- src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index eb8c1c466..20e10cdcd 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -196,7 +196,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { for (int j = 0; j < bits.length(); j++) { if (bits.get(j)) { - int value = 0; + int value; switch (j + 1) { case 1: -- cgit v1.2.3 From 2d36cb5e0bbad23064d75f1f9364094b3e2fefa5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 17 Sep 2022 17:00:48 -0700 Subject: Some Navis improvements --- src/main/java/org/traccar/protocol/NavisProtocolDecoder.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavisProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavisProtocolDecoder.java index 53631bd4e..77158b315 100644 --- a/src/main/java/org/traccar/protocol/NavisProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavisProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2022 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. @@ -24,7 +24,6 @@ import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.BitUtil; import org.traccar.helper.Checksum; -import org.traccar.helper.Checksum.Algorithm; import org.traccar.helper.DateBuilder; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; @@ -591,10 +590,8 @@ public class NavisProtocolDecoder extends BaseProtocolDecoder { private void sendFlexReply(Channel channel, ByteBuf data) { if (channel != null) { - ByteBuf cs = Unpooled.buffer(1); - cs.writeByte(Checksum.crc8(new Algorithm(8, 0x31, 0xFF, false, false, 0x00), data.nioBuffer())); - - channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(data, cs), channel.remoteAddress())); + data.writeByte(Checksum.crc8(Checksum.CRC8_EGTS, data.nioBuffer())); + channel.writeAndFlush(new NetworkMessage(data, channel.remoteAddress())); } } -- cgit v1.2.3 From 6864e0a0a067f432bead08331404d4b141959a64 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 17 Sep 2022 17:26:52 -0700 Subject: Navtelecom fuel temperature --- .../java/org/traccar/protocol/NavtelecomProtocolDecoder.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index 20e10cdcd..08b1a8d0f 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -278,11 +278,11 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { case 42: case 43: value = buf.readUnsignedShortLE(); - position.set("rs485Fuel" + (j + 2 - 38), (value < 65500) ? value : null); + position.set("fuel" + (j + 2 - 38), (value < 65500) ? value : null); break; case 44: value = buf.readUnsignedShortLE(); - position.set("rs232Fuel", (value < 65500) ? value : null); + position.set(Position.KEY_FUEL_LEVEL, (value < 65500) ? value : null); break; case 45: case 46: @@ -297,6 +297,14 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { Position.PREFIX_TEMP + (j + 2 - 45), (value != (byte) 0x80) ? value : null); break; + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + position.set("fuelTemp" + (j + 2 - 78), (int) buf.readByte()); + break; default: buf.skipBytes(getItemLength(j + 1)); break; -- cgit v1.2.3 From 43e04167d35c9f68eb5850f6e7e9f2723400957f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 18 Sep 2022 09:26:22 -0700 Subject: Decode TAT100 cell info --- .../traccar/protocol/TeltonikaProtocolDecoder.java | 44 +++++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index ff1f52eb1..4671a1088 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -342,16 +342,40 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } } - private void decodeNetwork(Position position) { - Integer cid = (Integer) position.getAttributes().remove("cid"); - Integer lac = (Integer) position.getAttributes().remove("lac"); - if (cid != null && lac != null) { - CellTower cellTower = CellTower.fromLacCid(getConfig(), lac, cid); - long operator = position.getInteger(Position.KEY_OPERATOR); - if (operator >= 1000) { - cellTower.setOperator(operator); + private void decodeCell( + Position position, Network network, String mncKey, String lacKey, String cidKey, String rssiKey) { + if (position.hasAttribute(mncKey) && position.hasAttribute(lacKey) && position.hasAttribute(cidKey)) { + CellTower cellTower = CellTower.from( + getConfig().getInteger(Keys.GEOLOCATION_MCC), + (Integer) position.getAttributes().remove(mncKey), + (Integer) position.getAttributes().remove(lacKey), + (Integer) position.getAttributes().remove(cidKey)); + cellTower.setSignalStrength((Integer) position.getAttributes().remove(rssiKey)); + network.addCellTower(cellTower); + } + } + + private void decodeNetwork(Position position, String model) { + if ("TAT100".equals(model)) { + Network network = new Network(); + decodeCell(position, network, "io1200", "io287", "io288", "io289"); + decodeCell(position, network, "io1201", "io290", "io291", "io292"); + decodeCell(position, network, "io1202", "io293", "io294", "io295"); + decodeCell(position, network, "io1203", "io296", "io297", "io298"); + if (network.getCellTowers() != null) { + position.setNetwork(network); + } + } else { + Integer cid = (Integer) position.getAttributes().remove("cid"); + Integer lac = (Integer) position.getAttributes().remove("lac"); + if (cid != null && lac != null) { + CellTower cellTower = CellTower.fromLacCid(getConfig(), lac, cid); + long operator = position.getInteger(Position.KEY_OPERATOR); + if (operator >= 1000) { + cellTower.setOperator(operator); + } + position.setNetwork(new Network(cellTower)); } - position.setNetwork(new Network(cellTower)); } } @@ -545,7 +569,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } } - decodeNetwork(position); + decodeNetwork(position, model); } -- cgit v1.2.3 From 4de8efe1ef0810af492c161bfc1d3200958d75d8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 18 Sep 2022 10:01:28 -0700 Subject: Refactor M-5000/10000 decoding --- src/main/java/org/traccar/helper/NMEA.java | 126 --------------------- .../traccar/protocol/PiligrimProtocolDecoder.java | 125 ++++++++------------ .../protocol/PiligrimProtocolDecoderTest.java | 4 + 3 files changed, 52 insertions(+), 203 deletions(-) delete mode 100644 src/main/java/org/traccar/helper/NMEA.java diff --git a/src/main/java/org/traccar/helper/NMEA.java b/src/main/java/org/traccar/helper/NMEA.java deleted file mode 100644 index cae47a8f6..000000000 --- a/src/main/java/org/traccar/helper/NMEA.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.traccar.helper; - -import java.util.HashMap; -import java.util.Map; - - -public class NMEA { - - // fucking java interfaces - interface SentenceParser { - public boolean parse(String[] tokens, GPSPosition position); - } - - // utils - static float Latitude2Decimal(String lat, String NS) { - float med = Float.parseFloat(lat.substring(2)) / 60.0f; - med += Float.parseFloat(lat.substring(0, 2)); - if (NS.startsWith("S")) { - med = -med; - } - return med; - } - - static float Longitude2Decimal(String lon, String WE) { - float med = Float.parseFloat(lon.substring(3)) / 60.0f; - med += Float.parseFloat(lon.substring(0, 3)); - if (WE.startsWith("W")) { - med = -med; - } - return med; - } - - // parsers - class GPGGA implements SentenceParser { - public boolean parse(String[] tokens, GPSPosition position) { - position.time = Float.parseFloat(tokens[1]); - position.lat = Latitude2Decimal(tokens[2], tokens[3]); - position.lon = Longitude2Decimal(tokens[4], tokens[5]); - position.quality = Integer.parseInt(tokens[6]); - position.altitude = Float.parseFloat(tokens[9]); - return true; - } - } - - class GPGGL implements SentenceParser { - public boolean parse(String[] tokens, GPSPosition position) { - position.lat = Latitude2Decimal(tokens[1], tokens[2]); - position.lon = Longitude2Decimal(tokens[3], tokens[4]); - position.time = Float.parseFloat(tokens[5]); - return true; - } - } - - class GPRMC implements SentenceParser { - public boolean parse(String[] tokens, GPSPosition position) { - position.time = Float.parseFloat(tokens[1]); - position.lat = Latitude2Decimal(tokens[3], tokens[4]); - position.lon = Longitude2Decimal(tokens[5], tokens[6]); - position.velocity = Float.parseFloat(tokens[7]); - position.dir = Float.parseFloat(tokens[8]); - return true; - } - } - - class GPVTG implements SentenceParser { - public boolean parse(String[] tokens, GPSPosition position) { - position.dir = Float.parseFloat(tokens[3]); - return true; - } - } - - class GPRMZ implements SentenceParser { - public boolean parse(String[] tokens, GPSPosition position) { - position.altitude = Float.parseFloat(tokens[1]); - return true; - } - } - - public class GPSPosition { - public float time = 0.0f; - public float lat = 0.0f; - public float lon = 0.0f; - public boolean fixed = false; - public int quality = 0; - public float dir = 0.0f; - public float altitude = 0.0f; - public float velocity = 0.0f; - - public void updatefix() { - fixed = quality > 0; - } - - public String toString() { - return String.format("POSITION: lat: %f, lon: %f, time: %f, Q: %d, dir: %f, alt: %f, vel: %f", lat, lon, time, quality, dir, altitude, velocity); - } - } - - GPSPosition position = new GPSPosition(); - - private static final Map sentenceParsers = new HashMap(); - - public NMEA() { - sentenceParsers.put("GPGGA", new GPGGA()); - sentenceParsers.put("GPGGL", new GPGGL()); - sentenceParsers.put("GPRMC", new GPRMC()); - sentenceParsers.put("GPRMZ", new GPRMZ()); - //only really good GPS devices have this sentence but ... - sentenceParsers.put("GPVTG", new GPVTG()); - } - - public GPSPosition parse(String line) { - - if (line.startsWith("$")) { - String nmea = line.substring(1); - String[] tokens = nmea.split(","); - String type = tokens[0]; - //TODO check crc - if (sentenceParsers.containsKey(type)) { - sentenceParsers.get(type).parse(tokens, position); - } - position.updatefix(); - } - - return position; - } -} diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index 6ca9b0795..34c879cb8 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2014 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,27 +21,23 @@ 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.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.traccar.BaseHttpProtocolDecoder; -import org.traccar.WebDataHandler; -import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.helper.BitUtil; import org.traccar.helper.DateBuilder; -import org.traccar.helper.NMEA; +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.nio.charset.StandardCharsets; -import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.regex.Pattern; public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { - private static final Logger LOGGER = LoggerFactory.getLogger(WebDataHandler.class); - public PiligrimProtocolDecoder(Protocol protocol) { super(protocol); } @@ -54,6 +50,21 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { public static final int MSG_GPS_SENSORS = 0xF2; public static final int MSG_EVENTS = 0xF3; + private static final Pattern PATTERN = new PatternBuilder() + .expression("[^$]+") + .text("$GPRMC,") + .number("(dd)(dd)(dd).d+,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d{2,3})(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.d+),") // speed + .number("(d+.d+),") // course + .number("(dd)(dd)(dd),") // date (ddmmyy) + .any() + .compile(); + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -157,82 +168,42 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { } return positions; + } else if (uri.startsWith("/push.do")) { + sendResponse(channel, "PUSH.DO: OK"); - /* Getting payload */ - ByteBuf contentStream = request.content(); - byte[] payloadBytes = new byte[Integer.parseInt(request.headers().get("Content-Length"))]; - contentStream.readBytes(payloadBytes); - String payload = new String(payloadBytes); - - /* Payload structure: - * &phone&message - */ - String[] payloadParts = payload.split("&"); - /* LOGGER.debug("Payload parts: " + Arrays.toString(payloadParts)); */ - String phoneNumber = payloadParts[1].substring(15); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, phoneNumber.substring(1)); + String sentence = request.content().toString(StandardCharsets.US_ASCII); + + String[] parts = sentence.split("&"); + String phone = parts[1].substring(16); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, phone); if (deviceSession == null) { return null; } - /* TODO: use keys for flags in 'positions'. */ - String message = payloadParts[2].substring(8).replaceFirst("[a-zA-Z! ]*; ", ""); - /* LOGGER.debug("Phone number: " + phoneNumber); */ - /* LOGGER.debug("Message: " + message); */ - - if (message.startsWith("$GPRMC")) { - /* Supported message structure: - * GPS NMEA Command; GSM info; Unknown; Battery voltage? - * Example: $GPRMC,180752.000,A,5314.0857,N,03421.8173,E,0.00,104.74,220722,,,A,V* 29,05; GSM: 250-01 0b54-0519,1c30,3e96,3ebe,412e 25; S; Batt: 405,M - */ - LOGGER.debug("Supported message"); - - String[] messageParts = message.split(";"); - /* LOGGER.debug("Message parts: " + Arrays.toString(messageParts)); */ - - /* Parsing GPS */ - String unprocessedGpsCommand = messageParts[0]; - - /* Getting rid of checksum */ - String gpsCommand = unprocessedGpsCommand.replaceFirst("A,V[*].*", ""); - /* LOGGER.debug("GPS command: " + gpsCommand); */ - - NMEA gpsParser = new NMEA(); - - NMEA.GPSPosition gpsPosition = gpsParser.parse(gpsCommand); - - /* LOGGER.debug("Time: " + gpsPosition.time); */ - /* LOGGER.debug("Coordinates: " + gpsPosition.lat + " " + gpsPosition.lon); */ - /* LOGGER.debug("Speed over ground: " + gpsPosition.velocity + " knots"); */ - - /* Parsing other fields */ - /* String gsmInfo = messageParts[1]; */ - /* String unknown = messageParts[2]; */ - String batteryInfo = messageParts[messageParts.length - 1].substring(7).substring(0, 3); - /* LOGGER.debug("Battery: " + batteryInfo); */ - - /* Constructing response */ - Position position = new Position(getProtocolName()); - - position.setDeviceId(deviceSession.getDeviceId()); - position.setValid(true); - position.setLatitude(gpsPosition.lat); - position.setLongitude(gpsPosition.lon); - position.setTime(new Date(System.currentTimeMillis())); - position.setSpeed(gpsPosition.velocity); - position.setCourse(gpsPosition.dir); - position.setAccuracy(gpsPosition.quality); - position.setAltitude(gpsPosition.altitude); - position.set(Position.KEY_BATTERY, Integer.parseInt(batteryInfo) / 100); - - LOGGER.debug("Supported message finish"); - - return position; - } else { - LOGGER.error("Unsupported message"); + Parser parser = new Parser(PATTERN, parts[2]); + if (!parser.matches()) { + return null; } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextDouble()); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + return position; + } return null; diff --git a/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java index 475ac0125..0dd00462d 100644 --- a/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java @@ -15,6 +15,10 @@ public class PiligrimProtocolDecoderTest extends ProtocolTest { "/bingps?imei=868204005544720&csq=18&vout=00&vin=4050&dataid=00000000", binary("fff2200d4110061a32354f3422310062000a0005173b0000a101000300005e00fff2200d4110100932354f2b22310042000b000e173b00009f01000700006000"))); + verifyPosition(decoder, request(HttpMethod.POST, + "/push.do", + buffer("&phoneNumber=%2B+78000000000&message=ALARM KEY; $GPRMC,180752.000,A,5314.0857,N,03421.8173,E,0.00,104.74,220722,,,A,V* 29,05; GSM: 250-01 0b54-0519,1c30,3e96,3ebe,412e 25; S; Batt: 405,M"))); + } } -- cgit v1.2.3 From 8532bffcec8e239c6699845e09e63da927f51d9a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 18 Sep 2022 10:47:58 -0700 Subject: Refactor NDTPv6 protocol --- .../org/traccar/protocol/NDTPv6FrameDecoder.java | 32 --- .../java/org/traccar/protocol/NDTPv6Protocol.java | 26 -- .../traccar/protocol/NDTPv6ProtocolDecoder.java | 309 --------------------- .../traccar/protocol/NDTPv6ProtocolEncoder.java | 38 --- .../org/traccar/protocol/NdtpV6FrameDecoder.java | 32 +++ .../java/org/traccar/protocol/NdtpV6Protocol.java | 39 +++ .../traccar/protocol/NdtpV6ProtocolDecoder.java | 203 ++++++++++++++ .../traccar/protocol/NdtpV6ProtocolEncoder.java | 42 +++ 8 files changed, 316 insertions(+), 405 deletions(-) delete mode 100644 src/main/java/org/traccar/protocol/NDTPv6FrameDecoder.java delete mode 100644 src/main/java/org/traccar/protocol/NDTPv6Protocol.java delete mode 100644 src/main/java/org/traccar/protocol/NDTPv6ProtocolDecoder.java delete mode 100644 src/main/java/org/traccar/protocol/NDTPv6ProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NdtpV6Protocol.java create mode 100644 src/main/java/org/traccar/protocol/NdtpV6ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NdtpV6ProtocolEncoder.java diff --git a/src/main/java/org/traccar/protocol/NDTPv6FrameDecoder.java b/src/main/java/org/traccar/protocol/NDTPv6FrameDecoder.java deleted file mode 100644 index c869b11a4..000000000 --- a/src/main/java/org/traccar/protocol/NDTPv6FrameDecoder.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.traccar.protocol; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class NDTPv6FrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - return buf; - } - -} diff --git a/src/main/java/org/traccar/protocol/NDTPv6Protocol.java b/src/main/java/org/traccar/protocol/NDTPv6Protocol.java deleted file mode 100644 index 78dc11b50..000000000 --- a/src/main/java/org/traccar/protocol/NDTPv6Protocol.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 2020 - NDTP v6 Protocol - */ -package org.traccar.protocol; - -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.config.Config; - -import javax.inject.Inject; - -public class NDTPv6Protocol extends BaseProtocol { - - @Inject - public NDTPv6Protocol(Config config) { - addServer( - new TrackerServer(config, getName(), false) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { - pipeline.addLast(new NDTPv6ProtocolDecoder(NDTPv6Protocol.this)); - } - } - ); - } -} diff --git a/src/main/java/org/traccar/protocol/NDTPv6ProtocolDecoder.java b/src/main/java/org/traccar/protocol/NDTPv6ProtocolDecoder.java deleted file mode 100644 index 788afd65b..000000000 --- a/src/main/java/org/traccar/protocol/NDTPv6ProtocolDecoder.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * 2020 - NDTP v6 Protocol Decoder - */ -package org.traccar.protocol; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; - -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Date; - -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.model.Position; -import org.traccar.session.DeviceSession; - -public class NDTPv6ProtocolDecoder extends BaseProtocolDecoder { - - public NDTPv6ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final byte[] SIGNATURE = {0x7E, 0x7E}; - - private static final int NPL_FLAG_CRC = 2; - private static final int NPH_RESULT_OK = 0x00000000; - private static final int NPL_TYPE_NPH = 2; - private static final int NPL_ADDRESS_SERVER = 0; - - /* common packets for all services */ - private static final int NPH_RESULT = 0; - - /* NPH service types */ - private static final int NPH_SRV_GENERIC_CONTROLS = 0; - private static final int NPH_SRV_NAVDATA = 1; - - /* NPH_SRV_GENERIC_CONTROLS packets */ - private static final int NPH_SGC_RESULT = NPH_RESULT; - private static final int NPH_SGC_CONN_REQUEST = 100; - - /* NPH_SRV_NAVDATA packets */ - private static final int NPH_SND_RESULT = NPH_RESULT; - - private static void sendResultResponse( - Channel channel, - short serviceId, - int requestId, - int nphSendResult, - int nphResult - ) { - // Формирование пакета данных - byte[] serviceIdBytes = ByteBuffer - .allocate(2) - .order(ByteOrder.LITTLE_ENDIAN) - .putShort(serviceId) - .array(); - byte[] nphSendResultBytes = ByteBuffer - .allocate(4) - .order(ByteOrder.LITTLE_ENDIAN) - .putInt(nphSendResult) - .array(); - byte[] requestIdBytes = ByteBuffer - .allocate(4) - .order(ByteOrder.LITTLE_ENDIAN) - .putInt(requestId) - .array(); - byte[] nphResultBytes = ByteBuffer - .allocate(4) - .order(ByteOrder.LITTLE_ENDIAN) - .putInt(nphResult) - .array(); - - byte[] allByteArray = new byte[serviceIdBytes.length + - requestIdBytes.length + - nphSendResultBytes.length + - nphResultBytes.length]; - - System.arraycopy(serviceIdBytes, 0, allByteArray, 0, serviceIdBytes.length); - System.arraycopy( - nphSendResultBytes, - 0, - allByteArray, - serviceIdBytes.length, - nphSendResultBytes.length - ); - System.arraycopy( - requestIdBytes, - 0, - allByteArray, - serviceIdBytes.length + nphSendResultBytes.length, - requestIdBytes.length - ); - System.arraycopy( - nphResultBytes, - 0, - allByteArray, - serviceIdBytes.length + requestIdBytes.length + nphSendResultBytes.length, - nphResultBytes.length - ); - - // ПАКЕТ ОТВЕТА КЛИЕНТУ - ByteBuf response = Unpooled.buffer(); - // NPL - response.writeBytes(SIGNATURE); - response.writeShortLE(allByteArray.length); // Размер данных - response.writeShortLE(NPL_FLAG_CRC); // Флаги - - response.writeShort( - Checksum.crc16(Checksum.CRC16_MODBUS, ByteBuffer.wrap(allByteArray)) - ); // CRC - response.writeByte(NPL_TYPE_NPH); // Тип - response.writeIntLE(NPL_ADDRESS_SERVER); // peer_address - response.writeShortLE(0); // request_id - - response.writeBytes(allByteArray); - - channel.writeAndFlush( - new NetworkMessage(response, channel.remoteAddress()) - ); - } - - private static final short MAIN_NAV_DATA = 0; - private static final short ADDITIONAL_NAV_DATA = 2; - - private void decodeData(ByteBuf buf, Position position, int dataType) { - if (dataType == NPH_SRV_NAVDATA) { - short cellType; - short cellNumber; - - cellType = buf.readUnsignedByte(); // Тип ячейки - cellNumber = buf.readUnsignedByte(); // Номер ячейки - if (cellType == MAIN_NAV_DATA && (cellNumber == 0 || cellNumber == 1)) { - position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); // Значение реального времени unix - position.setLongitude(buf.readIntLE() / 10000000.0); // Долгота в градусах, умноженная на 10 000 000 - position.setLatitude(buf.readIntLE() / 10000000.0); // Широта в градусах, умноженная на 10 000 000 - - short flags = buf.readUnsignedByte(); // Достоверность навигационных данных: - // bit7 - достоверность нав. данных (1 - достоверны, 0 – нет); - // bit6 - полушарие долготы (1 – E, 0 – W); - // bit5 - полушарие широты (1 – N, 0 – S); - // bit4 - флаг работы от встроенного аккумулятора; - // bit3 – флаг первоначального включения; - // bit2 – состояние SOS (1 – SOS, 0 – нет SOS); - // bit1 – флаг тревожной информации (один из параметров - // находится в диапазоне тревоги) - position.setValid(BitUtil.check(flags, 7)); - if (BitUtil.check(flags, 1)) { - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - } - position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 20); // Напряжение батареи, 1бит = 20мВ - position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShortLE()); // Средняя скорость за период в км/ч - position.setSpeed(buf.readUnsignedShortLE() / 1.85); // Максимальная скорость за период в км/ч - - int course = buf.readUnsignedShortLE(); // Направление движения - position.setCourse(course); - - position.set(Position.KEY_DISTANCE, buf.readUnsignedShortLE()); // Пройденный путь, м - position.setAltitude(buf.readShortLE()); // Высота над уровнем моря в метрах (-18000 - +18000) - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); // Количество видимых спутников - position.set(Position.KEY_PDOP, buf.readUnsignedByte()); // PDOP - } - cellType = buf.readUnsignedByte(); // Тип ячейки - cellNumber = buf.readUnsignedByte(); // Номер ячейки - if (cellType == ADDITIONAL_NAV_DATA && cellNumber == 0) { - int analogIn1 = buf.readUnsignedShortLE(); // Значение 0 аналогового входа в 16 битном формате - //(analogIn1 - отражает напряжение на батерии для радиоборта) - int analogIn2 = buf.readUnsignedShortLE(); // Значение 1 аналогового входа в 16 битном формате - int analogIn3 = buf.readUnsignedShortLE(); // Значение 2 аналогового входа в 16 битном формате - int analogIn4 = buf.readUnsignedShortLE(); // Значение 3 аналогового входа в 16 битном формате - - buf.readUnsignedByte(); // Значение цифровых входов - buf.readUnsignedByte(); // Состояние дискретных выходов - buf.readUnsignedShortLE(); // Количество импульсов на дискретном входе 0 с предыдущей нав. отметки - buf.readUnsignedShortLE(); // Количество импульсов на дискретном входе 1 с предыдущей нав. отметки - buf.readUnsignedShortLE(); // Количество импульсов на дискретном входе 2 с предыдущей нав. отметки - buf.readUnsignedShortLE(); // Количество импульсов на дискретном входе 3 с предыдущей нав. отметки - buf.readUnsignedIntLE(); // Длина трека с момента первого включения - - position.set(Position.KEY_ANTENNA, buf.readUnsignedByte()); // Сила GSM сигнала - position.set(Position.KEY_GPS, buf.readUnsignedByte()); // Состояние GPRS подключения - position.set(Position.KEY_ACCELERATION, buf.readUnsignedByte()); // Акселерометр - энергия - position.set(Position.KEY_POWER, buf.readUnsignedByte() * 200); // Напряжение борт. сети (1бит - 200мв) - - position.set(Position.PREFIX_ADC + 1, analogIn1 * 1); - position.set(Position.PREFIX_ADC + 2, analogIn2 * 1); - position.set(Position.PREFIX_ADC + 3, analogIn3 * 1); - position.set(Position.PREFIX_ADC + 4, analogIn4 * 1); - - // Расчет уровня батареи - // float Voltage = 5 / 4096 * analogIn1; // Вольтаж - - float batteryLevel = (analogIn1 - 3600) / 6; - - if (batteryLevel > 100) { - batteryLevel = 100; - } - if (batteryLevel < 0) { - batteryLevel = 0; - } - - position.set(Position.KEY_BATTERY_LEVEL, batteryLevel); - } - } - } - - @Override - protected Object decode( - Channel channel, - SocketAddress remoteAddress, - Object msg - ) - throws Exception { - ByteBuf buf = (ByteBuf) msg; - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - - // Заголовок NPL - buf.skipBytes(2); // Сигнатура (7e 7e) - buf.readUnsignedShortLE(); // Размер данных (nph + размер массива данных) - buf.readUnsignedShortLE(); // Флаги соединения (2 - проверять crc) - buf.readUnsignedShortLE(); // CRC (Modbus) - buf.readUnsignedByte(); // Тип пакета (nph) - buf.readUnsignedIntLE(); // Адрес участника соединения - buf.readUnsignedShortLE(); // Идентификатор NPL - - // Заголовок NPH - int serviceId = buf.readUnsignedShortLE(); // Идентификатор услуги (NPH_SRV_NAVDATA) service_id - int serviceType = buf.readUnsignedShortLE(); // Тип пакета - buf.readUnsignedShortLE(); // Флаг (1 - требуется подтверждение) NPH_FLAG_REQUEST - long requestId = buf.readUnsignedIntLE(); // Идентификатор nph - - if ( - deviceSession == null && - serviceId == NPH_SRV_GENERIC_CONTROLS && - serviceType == NPH_SGC_CONN_REQUEST - ) { // Регистрация устройства - buf.readUnsignedShortLE(); // Версия протокола NDTP (старший номер) - buf.readUnsignedShortLE(); // Версия протокола NDTP (младший номер) - buf.readUnsignedShortLE(); // Опции соединения (connection_flags) - // Определяет настройки соединения, - // которые будут использоваться после установки соединения. - // На данный момент их две: - // - бит0: шифровать пакеты (0 - нет, 1 — да) - // - бит1: рассчитывать CRC пакетов (0 - нет, 1 — да) - // - бит2: подключение симулятора (0 — подключается обычный клиент, - // 1 подключается симулятор) - // - бит3: тип алгоритма шифрования. - // - 0 - blowfish - // - 1 – ГОСТ - // - бит8: наличие поля IMEI (0 - нет, 1 — да) - // - бит9: наличие поля IMSI (0 - нет, 1 — да) - // - остальные биты не используются. - int deviceId = buf.readUnsignedShortLE(); - Position position = new Position(getProtocolName()); - deviceSession = - getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); - position.setDeviceId(deviceSession.getDeviceId()); - - if (channel != null) { - sendResultResponse( - channel, - (short) serviceId, - (int) requestId, - NPH_SND_RESULT, - NPH_RESULT_OK - ); - } - - position.set(Position.KEY_RESULT, String.valueOf(NPH_SGC_RESULT)); - position.setTime(new Date()); - getLastLocation(position, new Date()); - position.setValid(false); - - return position; - } - - if (serviceId == NPH_SRV_NAVDATA) { - deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (channel != null) { - sendResultResponse( - channel, - (short) serviceId, - (int) requestId, - NPH_SND_RESULT, - NPH_RESULT_OK - ); - } - - decodeData(buf, position, NPH_SRV_NAVDATA); - - return position; - } - - return null; - } -} diff --git a/src/main/java/org/traccar/protocol/NDTPv6ProtocolEncoder.java b/src/main/java/org/traccar/protocol/NDTPv6ProtocolEncoder.java deleted file mode 100644 index af0dd58f9..000000000 --- a/src/main/java/org/traccar/protocol/NDTPv6ProtocolEncoder.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 2020 - NDTP v6 Protocol Encoder - */ -package org.traccar.protocol; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import java.nio.charset.StandardCharsets; -import org.traccar.BaseProtocolEncoder; -import org.traccar.Protocol; -import org.traccar.model.Command; - -public class NDTPv6ProtocolEncoder extends BaseProtocolEncoder { - - public NDTPv6ProtocolEncoder(Protocol protocol) { - super(protocol); - } - - private ByteBuf encodeCommand(String commandString) { - ByteBuf buffer = Unpooled.buffer(); - buffer.writeBytes(commandString.getBytes(StandardCharsets.US_ASCII)); - return buffer; - } - - @Override - protected Object encodeCommand(Command command) { - switch (command.getType()) { - case Command.TYPE_IDENTIFICATION: - return encodeCommand("BB+IDNT"); - case Command.TYPE_REBOOT_DEVICE: - return encodeCommand("BB+RESET"); - case Command.TYPE_POSITION_SINGLE: - return encodeCommand("BB+RRCD"); - default: - return null; - } - } -} diff --git a/src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java b/src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java new file mode 100644 index 000000000..5b610013a --- /dev/null +++ b/src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java @@ -0,0 +1,32 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class NdtpV6FrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + return buf; + } + +} diff --git a/src/main/java/org/traccar/protocol/NdtpV6Protocol.java b/src/main/java/org/traccar/protocol/NdtpV6Protocol.java new file mode 100644 index 000000000..ce0dbbef2 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NdtpV6Protocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2022 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.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +import javax.inject.Inject; + +public class NdtpV6Protocol extends BaseProtocol { + + @Inject + public NdtpV6Protocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new NdtpV6ProtocolDecoder(NdtpV6Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/NdtpV6ProtocolDecoder.java b/src/main/java/org/traccar/protocol/NdtpV6ProtocolDecoder.java new file mode 100644 index 000000000..35cb0bae8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NdtpV6ProtocolDecoder.java @@ -0,0 +1,203 @@ +/* + * Copyright 2022 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; + +public class NdtpV6ProtocolDecoder extends BaseProtocolDecoder { + + public NdtpV6ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final byte[] SIGNATURE = {0x7E, 0x7E}; + + private static final int NPL_FLAG_CRC = 2; + private static final int NPH_RESULT_OK = 0x00000000; + private static final int NPL_TYPE_NPH = 2; + private static final int NPL_ADDRESS_SERVER = 0; + + private static final int NPH_RESULT = 0; + + private static final int NPH_SRV_GENERIC_CONTROLS = 0; + private static final int NPH_SRV_NAVDATA = 1; + + private static final int NPH_SGC_RESULT = NPH_RESULT; + private static final int NPH_SGC_CONN_REQUEST = 100; + + private static final int NPH_SND_RESULT = NPH_RESULT; + + private void sendResponse( + Channel channel, int serviceId, long requestId) { + + ByteBuf content = Unpooled.buffer(); + content.writeShortLE(serviceId); + content.writeIntLE(NPH_SND_RESULT); + content.writeIntLE((int) requestId); + content.writeIntLE(NPH_RESULT_OK); + + ByteBuf response = Unpooled.buffer(); + response.writeBytes(SIGNATURE); + response.writeShortLE(content.readableBytes()); + response.writeShortLE(NPL_FLAG_CRC); // flags + response.writeShort(Checksum.crc16(Checksum.CRC16_MODBUS, content.nioBuffer())); + response.writeByte(NPL_TYPE_NPH); // type + response.writeIntLE(NPL_ADDRESS_SERVER); // peer address + response.writeShortLE(0); // request id + response.writeBytes(content); + content.release(); + + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + + private static final short MAIN_NAV_DATA = 0; + private static final short ADDITIONAL_NAV_DATA = 2; + + private void decodeData(ByteBuf buf, Position position) { + + short itemType; + short itemIndex; + + itemType = buf.readUnsignedByte(); + itemIndex = buf.readUnsignedByte(); + if (itemType == MAIN_NAV_DATA && (itemIndex == 0 || itemIndex == 1)) { + + position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); + position.setLongitude(buf.readIntLE() / 10000000.0); + position.setLatitude(buf.readIntLE() / 10000000.0); + + short flags = buf.readUnsignedByte(); + position.setValid(BitUtil.check(flags, 7)); + if (BitUtil.check(flags, 1)) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + + position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 20); + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShortLE()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); + position.setCourse(buf.readUnsignedShortLE()); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedShortLE()); + position.setAltitude(buf.readShortLE()); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_PDOP, buf.readUnsignedByte()); + } + + itemType = buf.readUnsignedByte(); + itemIndex = buf.readUnsignedByte(); + if (itemType == ADDITIONAL_NAV_DATA && itemIndex == 0) { + + position.set(Position.KEY_BATTERY_LEVEL, Math.max((buf.readUnsignedShortLE() - 3600) / 6, 100)); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE()); + position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShortLE()); + position.set(Position.PREFIX_ADC + 4, buf.readUnsignedShortLE()); + + buf.readUnsignedByte(); // inputs + buf.readUnsignedByte(); // outputs + buf.readUnsignedShortLE(); // in1 count + buf.readUnsignedShortLE(); // in2 count + buf.readUnsignedShortLE(); // in3 count + buf.readUnsignedShortLE(); // in4 count + buf.readUnsignedIntLE(); // track length + + position.set(Position.KEY_ANTENNA, buf.readUnsignedByte()); + position.set(Position.KEY_GPS, buf.readUnsignedByte()); + position.set(Position.KEY_ACCELERATION, buf.readUnsignedByte()); + position.set(Position.KEY_POWER, buf.readUnsignedByte() * 200); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + + buf.skipBytes(2); // signature + buf.readUnsignedShortLE(); // length + buf.readUnsignedShortLE(); // connection flags + buf.readUnsignedShortLE(); // checksum + buf.readUnsignedByte(); // type + buf.readUnsignedIntLE(); // address + buf.readUnsignedShortLE(); // identification + + int serviceId = buf.readUnsignedShortLE(); + int serviceType = buf.readUnsignedShortLE(); + buf.readUnsignedShortLE(); // request flags + long requestId = buf.readUnsignedIntLE(); + + if (deviceSession == null && serviceId == NPH_SRV_GENERIC_CONTROLS && serviceType == NPH_SGC_CONN_REQUEST) { + + buf.readUnsignedShortLE(); // version major + buf.readUnsignedShortLE(); // version minor + buf.readUnsignedShortLE(); // connection flags + + int deviceId = buf.readUnsignedShortLE(); + Position position = new Position(getProtocolName()); + deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); + position.setDeviceId(deviceSession.getDeviceId()); + + if (channel != null) { + sendResponse(channel, serviceId, requestId); + } + + position.set(Position.KEY_RESULT, String.valueOf(NPH_SGC_RESULT)); + position.setTime(new Date()); + getLastLocation(position, new Date()); + position.setValid(false); + + return position; + + } + + if (serviceId == NPH_SRV_NAVDATA) { + + deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (channel != null) { + sendResponse(channel, serviceId, requestId); + } + + decodeData(buf, position); + + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/NdtpV6ProtocolEncoder.java b/src/main/java/org/traccar/protocol/NdtpV6ProtocolEncoder.java new file mode 100644 index 000000000..7aac8658a --- /dev/null +++ b/src/main/java/org/traccar/protocol/NdtpV6ProtocolEncoder.java @@ -0,0 +1,42 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import org.traccar.BaseProtocolEncoder; +import org.traccar.Protocol; +import org.traccar.model.Command; + +public class NdtpV6ProtocolEncoder extends BaseProtocolEncoder { + + public NdtpV6ProtocolEncoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object encodeCommand(Command command) { + switch (command.getType()) { + case Command.TYPE_IDENTIFICATION: + return "BB+IDNT"; + case Command.TYPE_REBOOT_DEVICE: + return "BB+RESET"; + case Command.TYPE_POSITION_SINGLE: + return "BB+RRCD"; + default: + return null; + } + } + +} -- cgit v1.2.3