aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java')
-rw-r--r--src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java1388
1 files changed, 815 insertions, 573 deletions
diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java
index 517499f02..2e5ffa8d6 100644
--- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2024 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,12 +15,15 @@
*/
package org.traccar.protocol;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.config.Keys;
import org.traccar.helper.BitUtil;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
import org.traccar.helper.UnitsConverter;
@@ -28,15 +31,14 @@ import org.traccar.model.CellTower;
import org.traccar.model.Network;
import org.traccar.model.Position;
import org.traccar.model.WifiAccessPoint;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.Channel;
+import org.traccar.session.DeviceSession;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.TimeZone;
@@ -47,8 +49,12 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
private boolean ignoreFixTime;
+ private final DateFormat dateFormat;
+
public Gl200TextProtocolDecoder(Protocol protocol) {
super(protocol);
+ dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
}
@Override
@@ -56,21 +62,67 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
ignoreFixTime = getConfig().getBoolean(Keys.PROTOCOL_IGNORE_FIX_TIME.withPrefix(getProtocolName()));
}
- private static final Pattern PATTERN_ACK = new PatternBuilder()
- .text("+ACK:GT")
- .expression("...,") // type
- .number("([0-9A-Z]{2}xxxx),") // protocol version
- .number("(d{15}|x{14}),") // imei
- .any().text(",")
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd),") // time (hhmmss)
- .number("(xxxx)") // counter
- .text("$").optional()
- .compile();
+ private String getDeviceModel(DeviceSession deviceSession, String value) {
+ String model = value.isEmpty() ? getDeviceModel(deviceSession) : value;
+ return model != null ? model.toUpperCase() : "";
+ }
+
+ private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) {
+ if (parser.matches()) {
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession != null) {
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+ return position;
+ }
+ }
+ return null;
+ }
+
+ private void decodeDeviceTime(Position position, Parser parser) {
+ if (parser.hasNext(6)) {
+ if (ignoreFixTime) {
+ position.setTime(parser.nextDateTime());
+ } else {
+ position.setDeviceTime(parser.nextDateTime());
+ }
+ }
+ }
+
+ private Long parseHours(String hoursString) {
+ if (hoursString != null && !hoursString.isEmpty()) {
+ String[] hours = hoursString.split(":");
+ return (Integer.parseInt(hours[0]) * 3600L
+ + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60L : 0)
+ + (hours.length > 2 ? Integer.parseInt(hours[2]) : 0)) * 1000;
+ }
+ return null;
+ }
+
+ private Position decodeAck(Channel channel, SocketAddress remoteAddress, String[] values) throws ParseException {
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[2]);
+ if (deviceSession == null) {
+ return null;
+ }
+ if (values[0].equals("+ACK:GTHBD")) {
+ if (channel != null) {
+ channel.writeAndFlush(new NetworkMessage(
+ "+SACK:GTHBD," + values[1] + "," + values[values.length - 1] + "$", remoteAddress));
+ }
+ } else {
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+ getLastLocation(position, dateFormat.parse(values[values.length - 2]));
+ position.setValid(false);
+ position.set(Position.KEY_RESULT, values[0]);
+ return position;
+ }
+ return null;
+ }
private static final Pattern PATTERN_INF = new PatternBuilder()
.text("+").expression("(?:RESP|BUFF):GTINF,")
- .number("[0-9A-Z]{2}xxxx,") // protocol version
+ .expression("(?:.{6}|.{10})?,") // protocol version
.number("(d{15}|x{14}),") // imei
.expression("(?:[0-9A-Z]{17},)?") // vin
.expression("(?:[^,]+)?,") // device name
@@ -109,374 +161,6 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
.text("$").optional()
.compile();
- private static final Pattern PATTERN_VER = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF):GTVER,")
- .number("[0-9A-Z]{2}xxxx,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .expression("([^,]*),") // device type
- .number("(xxxx),") // firmware version
- .number("(xxxx),") // hardware version
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd),") // time (hhmmss)
- .number("(xxxx)") // counter
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_LOCATION = new PatternBuilder()
- .number("(d{1,2}.?d?)?,") // hdop
- .number("(d{1,3}.d)?,") // speed
- .number("(d{1,3}.?d?)?,") // course
- .number("(-?d{1,5}.d)?,") // altitude
- .number("(-?d{1,3}.d{6})?,") // longitude
- .number("(-?d{1,2}.d{6})?,") // latitude
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(d+)?,") // mcc
- .number("(d+)?,") // mnc
- .groupBegin()
- .number("(d+),") // lac
- .number("(d+),") // cid
- .or()
- .number("(x+)?,") // lac
- .number("(x+)?,") // cid
- .groupEnd()
- .number("(?:d+|(d+.d))?,") // rssi / odometer
- .compile();
-
- private static final Pattern PATTERN_OBD = new PatternBuilder()
- .text("+RESP:GTOBD,")
- .number("[0-9A-Z]{2}xxxx,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("(?:[0-9A-Z]{17})?,") // vin
- .expression("[^,]{0,20},") // device name
- .expression("[01],") // report type
- .number("x{1,8},") // report mask
- .expression("(?:[0-9A-Z]{17})?,") // vin
- .number("[01],") // obd connect
- .number("(?:d{1,5})?,") // obd voltage
- .number("(?:x{8})?,") // support pids
- .number("(d{1,5})?,") // engine rpm
- .number("(d{1,3})?,") // speed
- .number("(-?d{1,3})?,") // coolant temp
- .number("(d+.?d*|Inf|NaN)?,") // fuel consumption
- .number("(d{1,5})?,") // dtcs cleared distance
- .number("(?:d{1,5})?,")
- .expression("([01])?,") // obd connect
- .number("(d{1,3})?,") // number of dtcs
- .number("(x*),") // dtcs
- .number("(d{1,3})?,") // throttle
- .number("(?:d{1,3})?,") // engine load
- .number("(d{1,3})?,") // fuel level
- .expression("(?:[0-9A],)?") // obd protocol
- .number("(d+),") // odometer
- .expression(PATTERN_LOCATION.pattern())
- .number("(d{1,7}.d)?,") // odometer
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_FRI = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF):GT...,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("(?:([0-9A-Z]{17}),)?") // vin
- .expression("[^,]*,") // device name
- .number("(d+)?,") // power
- .number("(d{1,2}),").optional() // report type
- .number("d{1,2},").optional() // count
- .number("d*,").optional() // reserved
- .number("(d+),").optional() // battery
- .expression("((?:")
- .expression(PATTERN_LOCATION.pattern())
- .expression(")+)")
- .groupBegin()
- .number("d{1,2},,")
- .number("(d{1,3}),") // battery
- .number("[01],") // mode
- .number("(?:[01])?,") // motion
- .number("(?:-?d{1,2}.d)?,") // temperature
- .or()
- .number("(d{1,7}.d)?,") // odometer
- .number("(d{5}:dd:dd)?,") // hour meter
- .number("(x+)?,") // adc 1
- .number("(x+)?,") // adc 2
- .number("(d{1,3})?,") // battery
- .number("(?:(xx)(xx)(xx))?,") // device status
- .number("(d+)?,") // rpm
- .number("(?:d+.?d*|Inf|NaN)?,") // fuel consumption
- .number("(d+)?,") // fuel level
- .or()
- .number("(-?d),") // rssi
- .number("(d{1,3}),") // battery
- .or()
- .number("(d{1,7}.d)?,").optional() // odometer
- .number("(d{1,3})?,") // battery
- .groupEnd()
- .any()
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_ERI = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF):GTERI,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("(x{8}),") // mask
- .number("(d+)?,") // power
- .number("d{1,2},") // report type
- .number("d{1,2},") // count
- .expression("((?:")
- .expression(PATTERN_LOCATION.pattern())
- .expression(")+)")
- .groupBegin()
- .number("(d{1,7}.d)?,") // odometer
- .number("(d{5}:dd:dd)?,") // hour meter
- .number("(x+)?,") // adc 1
- .number("(x+)?,").optional() // adc 2
- .groupBegin()
- .number("(x+)?,") // adc 3
- .number("(xx),") // inputs
- .number("(xx),") // outputs
- .or()
- .number("(d{1,3})?,") // battery
- .number("(?:(xx)(xx)(xx))?,") // device status
- .groupEnd()
- .expression("(.*)") // additional data
- .or()
- .number("d*,,")
- .number("(d+),") // battery
- .any()
- .groupEnd()
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_IGN = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF):GTIG[NF],")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("d+,") // ignition off duration
- .expression(PATTERN_LOCATION.pattern())
- .number("(d{5}:dd:dd)?,") // hour meter
- .number("(d{1,7}.d)?,") // odometer
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_LSW = new PatternBuilder()
- .text("+RESP:").expression("GT[LT]SW,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("[01],") // type
- .number("([01]),") // state
- .expression(PATTERN_LOCATION.pattern())
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_IDA = new PatternBuilder()
- .text("+RESP:GTIDA,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,,") // device name
- .number("([^,]+),") // rfid
- .expression("[01],") // report type
- .number("1,") // count
- .expression(PATTERN_LOCATION.pattern())
- .number("(d+.d),") // odometer
- .text(",,,,")
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_WIF = new PatternBuilder()
- .text("+RESP:GTWIF,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("(d+),") // count
- .number("((?:x{12},-?d+,,,,)+),,,,") // wifi
- .number("(d{1,3}),") // battery
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_GSM = new PatternBuilder()
- .text("+RESP:GTGSM,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("(?:STR|CTN|NMR|RTL),") // fix type
- .expression("(.*)") // cells
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_PNA = new PatternBuilder()
- .text("+RESP:GT").expression("P[NF]A,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_DAR = new PatternBuilder()
- .text("+RESP:GTDAR,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("(d),") // warning type
- .number("(d{1,2}),,,") // fatigue degree
- .expression(PATTERN_LOCATION.pattern())
- .any()
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF):GT...,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("d*,")
- .number("(x{1,2}),") // report type
- .number("d{1,2},") // count
- .number("d*,").optional() // reserved
- .expression(PATTERN_LOCATION.pattern())
- .groupBegin()
- .number("(?:(d{1,7}.d)|0)?,").optional() // odometer
- .number("(d{1,3})?,") // battery
- .or()
- .number("(d{1,7}.d)?,") // odometer
- .groupEnd()
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)") // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_BASIC = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF)").text(":")
- .expression("GT...,")
- .number("(?:[0-9A-Z]{2}xxxx)?,").optional() // protocol version
- .number("(d{15}|x{14}),") // imei
- .any()
- .text(",")
- .number("(d{1,2})?,") // hdop
- .number("(d{1,3}.d)?,") // speed
- .number("(d{1,3})?,") // course
- .number("(-?d{1,5}.d)?,") // altitude
- .number("(-?d{1,3}.d{6})?,") // longitude
- .number("(-?d{1,2}.d{6})?,") // latitude
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(d+),") // mcc
- .number("(d+),") // mnc
- .number("(x+),") // lac
- .number("(x+),").optional(4) // cell
- .any()
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private Object decodeAck(Channel channel, SocketAddress remoteAddress, String sentence, String type) {
- Parser parser = new Parser(PATTERN_ACK, sentence);
- if (parser.matches()) {
- String protocolVersion = parser.next();
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
- if (deviceSession == null) {
- return null;
- }
- if (type.equals("HBD")) {
- if (channel != null) {
- parser.skip(6);
- channel.writeAndFlush(new NetworkMessage(
- "+SACK:GTHBD," + protocolVersion + "," + parser.next() + "$", remoteAddress));
- }
- } else {
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
- getLastLocation(position, parser.nextDateTime());
- position.setValid(false);
- position.set(Position.KEY_RESULT, "Command " + type + " accepted");
- return position;
- }
- }
- return null;
- }
-
- private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) {
- if (parser.matches()) {
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
- if (deviceSession != null) {
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
- return position;
- }
- }
- return null;
- }
-
- private void decodeDeviceTime(Position position, Parser parser) {
- if (parser.hasNext(6)) {
- if (ignoreFixTime) {
- position.setTime(parser.nextDateTime());
- } else {
- position.setDeviceTime(parser.nextDateTime());
- }
- }
- }
-
- private Long parseHours(String hoursString) {
- if (hoursString != null) {
- String[] hours = hoursString.split(":");
- return (long) (Integer.parseInt(hours[0]) * 3600
- + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60 : 0)
- + (hours.length > 2 ? Integer.parseInt(hours[2]) : 0)) * 1000;
- }
- return null;
- }
-
private Object decodeInf(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_INF, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -537,6 +221,20 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_VER = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF):GTVER,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .expression("([^,]*),") // device type
+ .number("(xxxx),") // firmware version
+ .number("(xxxx),") // hardware version
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("(xxxx)") // counter
+ .text("$").optional()
+ .compile();
+
private Object decodeVer(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_VER, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -554,9 +252,35 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
}
private void skipLocation(Parser parser) {
- parser.skip(19);
+ parser.skip(20);
}
+ private static final Pattern PATTERN_LOCATION = new PatternBuilder()
+ .number("(d{1,2}.?d?)?,") // hdop
+ .number("(d{1,3}.d)?,") // speed
+ .number("(d{1,3}.?d?)?,") // course
+ .number("(-?d{1,5}.d)?,") // altitude
+ .number("(-?d{1,3}.d{6})?,") // longitude
+ .number("(-?d{1,2}.d{6})?,") // latitude
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .groupBegin()
+ .number(",d+") // wifi count
+ .number("((?:,x{12},-d+,,,)+)") // wifi
+ .groupEnd("?")
+ .text(",")
+ .number("(d+)?,") // mcc
+ .number("(d+)?,") // mnc
+ .groupBegin()
+ .number("(d+),") // lac
+ .number("(d+),") // cid
+ .or()
+ .number("(x+)?,") // lac
+ .number("(x+)?,") // cid
+ .groupEnd()
+ .number("(?:d+|(d+.d))?,") // rssi / odometer
+ .compile();
+
private void decodeLocation(Position position, Parser parser) {
Double hdop = parser.nextDouble();
position.setValid(hdop == null || hdop > 0);
@@ -575,22 +299,125 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, null);
}
+ Network network = new Network();
+
+ if (parser.hasNext()) {
+ String[] values = parser.next().split(",");
+ for (int i = 0; i < values.length; i += 5) {
+ String mac = values[i + 1].replaceAll("(..)", "$1:");
+ network.addWifiAccessPoint(WifiAccessPoint.from(
+ mac.substring(0, mac.length() - 1), Integer.parseInt(values[i + 2])));
+ }
+ }
+
if (parser.hasNext(6)) {
int mcc = parser.nextInt();
int mnc = parser.nextInt();
if (parser.hasNext(2)) {
- position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextInt(), parser.nextInt())));
+ network.addCellTower(CellTower.from(mcc, mnc, parser.nextInt(), parser.nextInt()));
}
if (parser.hasNext(2)) {
- position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt())));
+ network.addCellTower(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt()));
}
}
+ if (network.getWifiAccessPoints() != null || network.getCellTowers() != null) {
+ position.setNetwork(network);
+ }
+
if (parser.hasNext()) {
position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
}
}
+ private int decodeLocation(Position position, String model, String[] values, int index) throws ParseException {
+ double hdop = values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1]);
+ position.set(Position.KEY_HDOP, hdop);
+
+ position.setSpeed(UnitsConverter.knotsFromKph(
+ values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1])));
+ position.setCourse(values[index++].isEmpty() ? 0 : Integer.parseInt(values[index - 1]));
+ position.setAltitude(values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1]));
+
+ if (!values[index].isEmpty()) {
+ position.setValid(true);
+ position.setLongitude(values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1]));
+ position.setLatitude(values[index++].isEmpty() ? 0 : Double.parseDouble(values[index - 1]));
+ position.setTime(dateFormat.parse(values[index++]));
+ } else {
+ index += 3;
+ getLastLocation(position, null);
+ }
+
+ Network network = new Network();
+
+ if (!values[index].isEmpty()) {
+ network.addCellTower(CellTower.from(
+ Integer.parseInt(values[index++]),
+ Integer.parseInt(values[index++]),
+ Integer.parseInt(values[index++], 16),
+ Long.parseLong(values[index++], 16)));
+ } else {
+ index += 4;
+ }
+
+ if (network.getWifiAccessPoints() != null || network.getCellTowers() != null) {
+ position.setNetwork(network);
+ }
+
+ if (model.startsWith("GL5")) {
+ index += 1; // csq rssi
+ index += 1; // csq ber
+ }
+
+ if (!values[index++].isEmpty()) {
+ int appendMask = Integer.parseInt(values[index - 1]);
+ if (BitUtil.check(appendMask, 0)) {
+ position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++]));
+ }
+ if (BitUtil.check(appendMask, 1)) {
+ index += 1; // trigger type
+ }
+ }
+
+ return index;
+ }
+
+ private static final Pattern PATTERN_OBD = new PatternBuilder()
+ .text("+RESP:GTOBD,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("(?:[0-9A-Z]{17})?,") // vin
+ .expression("[^,]{0,20},") // device name
+ .expression("[01],") // report type
+ .number("x{1,8},") // report mask
+ .expression("(?:[0-9A-Z]{17})?,") // vin
+ .number("[01],") // obd connect
+ .number("(?:d{1,5})?,") // obd voltage
+ .number("(?:x{8})?,") // support pids
+ .number("(d{1,5})?,") // engine rpm
+ .number("(d{1,3})?,") // speed
+ .number("(-?d{1,3})?,") // coolant temp
+ .number("(d+.?d*|Inf|NaN)?,") // fuel consumption
+ .number("(d{1,5})?,") // dtcs cleared distance
+ .number("(?:d{1,5})?,")
+ .expression("([01])?,") // obd connect
+ .number("(d{1,3})?,") // number of dtcs
+ .number("(x*),") // dtcs
+ .number("(d{1,3})?,") // throttle
+ .number("(?:d{1,3})?,") // engine load
+ .number("(d{1,3})?,") // fuel level
+ .expression("(?:[0-9A],)?") // obd protocol
+ .number("(d+),") // odometer
+ .expression(PATTERN_LOCATION.pattern())
+ .number("(d{1,7}.d)?,") // odometer
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_OBD, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -625,104 +452,140 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
- private Object decodeCan(Channel channel, SocketAddress remoteAddress, String sentence) throws ParseException {
- Position position = new Position(getProtocolName());
-
+ private Object decodeCan(Channel channel, SocketAddress remoteAddress, String[] v) throws ParseException {
int index = 0;
- String[] values = sentence.split(",");
-
index += 1; // header
index += 1; // protocol version
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, v[index++]);
+ if (deviceSession == null) {
+ return null;
+ }
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]);
+ Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
- index += 1; // device name
+ String model = getDeviceModel(deviceSession, v[index++]);
index += 1; // report type
- index += 1; // canbus state
- long reportMask = Long.parseLong(values[index++], 16);
+ index += 1; // can bus state
+ long reportMask = Long.parseLong(v[index++], 16);
long reportMaskExt = 0;
if (BitUtil.check(reportMask, 0)) {
- position.set(Position.KEY_VIN, values[index++]);
+ position.set(Position.KEY_VIN, v[index++]);
}
- if (BitUtil.check(reportMask, 1)) {
- position.set(Position.KEY_IGNITION, Integer.parseInt(values[index++]) > 0);
+ if (BitUtil.check(reportMask, 1) && !v[index++].isEmpty()) {
+ position.set(Position.KEY_IGNITION, Integer.parseInt(v[index - 1]) > 0);
}
- if (BitUtil.check(reportMask, 2)) {
- position.set(Position.KEY_OBD_ODOMETER, values[index++]);
+ if (BitUtil.check(reportMask, 2) && !v[index++].isEmpty()) {
+ position.set(Position.KEY_OBD_ODOMETER, Integer.parseInt(v[index - 1].substring(1)));
}
- if (BitUtil.check(reportMask, 3) && !values[index++].isEmpty()) {
- position.set(Position.KEY_FUEL_USED, Double.parseDouble(values[index - 1]));
+ if (BitUtil.check(reportMask, 3) && !v[index++].isEmpty()) {
+ position.set(Position.KEY_FUEL_USED, Double.parseDouble(v[index - 1]));
}
- if (BitUtil.check(reportMask, 5) && !values[index++].isEmpty()) {
- position.set(Position.KEY_RPM, Integer.parseInt(values[index - 1]));
+ if (BitUtil.check(reportMask, 5) && !v[index++].isEmpty()) {
+ position.set(Position.KEY_RPM, Integer.parseInt(v[index - 1]));
}
- if (BitUtil.check(reportMask, 4) && !values[index++].isEmpty()) {
- position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(Integer.parseInt(values[index - 1])));
+ if (BitUtil.check(reportMask, 4) && !v[index++].isEmpty()) {
+ position.set(Position.KEY_OBD_SPEED, Integer.parseInt(v[index - 1]));
}
- if (BitUtil.check(reportMask, 6) && !values[index++].isEmpty()) {
- position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(values[index - 1]));
+ if (BitUtil.check(reportMask, 6) && !v[index++].isEmpty()) {
+ position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(v[index - 1]));
}
- if (BitUtil.check(reportMask, 7) && !values[index++].isEmpty()) {
- position.set(Position.KEY_FUEL_CONSUMPTION, Double.parseDouble(values[index - 1].substring(1)));
+ if (BitUtil.check(reportMask, 7) && !v[index++].isEmpty()) {
+ String value = v[index - 1];
+ if (value.startsWith("L/H")) {
+ position.set(Position.KEY_FUEL_CONSUMPTION, Double.parseDouble(value.substring(3)));
+ }
}
- if (BitUtil.check(reportMask, 8) && !values[index++].isEmpty()) {
- position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(values[index - 1].substring(1)));
+ if (BitUtil.check(reportMask, 8) && !v[index++].isEmpty()) {
+ position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(v[index - 1].substring(1)));
}
- if (BitUtil.check(reportMask, 9) && !values[index++].isEmpty()) {
- position.set("range", Long.parseLong(values[index - 1]) * 100);
+ if (BitUtil.check(reportMask, 9) && !v[index++].isEmpty()) {
+ position.set("range", Long.parseLong(v[index - 1]) * 100);
}
- if (BitUtil.check(reportMask, 10) && !values[index++].isEmpty()) {
- position.set(Position.KEY_THROTTLE, Integer.parseInt(values[index - 1]));
+ if (BitUtil.check(reportMask, 10) && !v[index++].isEmpty()) {
+ position.set(Position.KEY_THROTTLE, Integer.parseInt(v[index - 1]));
}
- if (BitUtil.check(reportMask, 11) && !values[index++].isEmpty()) {
- position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(Double.parseDouble(values[index - 1])));
+ if (BitUtil.check(reportMask, 11) && !v[index++].isEmpty()) {
+ position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(Double.parseDouble(v[index - 1])));
}
- if (BitUtil.check(reportMask, 12)) {
- position.set("drivingHours", Double.parseDouble(values[index++]));
+ if (BitUtil.check(reportMask, 12) && !v[index++].isEmpty()) {
+ position.set(Position.KEY_DRIVING_TIME, Double.parseDouble(v[index - 1]));
}
- if (BitUtil.check(reportMask, 13)) {
- position.set("idleHours", Double.parseDouble(values[index++]));
+ if (BitUtil.check(reportMask, 13) && !v[index++].isEmpty()) {
+ position.set("idleHours", Double.parseDouble(v[index - 1]));
}
- if (BitUtil.check(reportMask, 14) && !values[index++].isEmpty()) {
- position.set("idleFuelConsumption", Double.parseDouble(values[index - 1]));
+ if (BitUtil.check(reportMask, 14) && !v[index++].isEmpty()) {
+ position.set("idleFuelConsumption", Double.parseDouble(v[index - 1]));
}
- if (BitUtil.check(reportMask, 15) && !values[index++].isEmpty()) {
- position.set(Position.KEY_AXLE_WEIGHT, Integer.parseInt(values[index - 1]));
+ if (BitUtil.check(reportMask, 15) && !v[index++].isEmpty()) {
+ position.set(Position.KEY_AXLE_WEIGHT, Integer.parseInt(v[index - 1]));
}
- if (BitUtil.check(reportMask, 16) && !values[index++].isEmpty()) {
- position.set("tachographInfo", Integer.parseInt(values[index - 1], 16));
+ if (BitUtil.check(reportMask, 16) && !v[index++].isEmpty()) {
+ position.set("tachographInfo", Integer.parseInt(v[index - 1], 16));
}
- if (BitUtil.check(reportMask, 17) && !values[index++].isEmpty()) {
- position.set("indicators", Integer.parseInt(values[index - 1], 16));
+ if (BitUtil.check(reportMask, 17) && !v[index++].isEmpty()) {
+ position.set("indicators", Integer.parseInt(v[index - 1], 16));
}
- if (BitUtil.check(reportMask, 18) && !values[index++].isEmpty()) {
- position.set("lights", Integer.parseInt(values[index - 1], 16));
+ if (BitUtil.check(reportMask, 18) && !v[index++].isEmpty()) {
+ position.set("lights", Integer.parseInt(v[index - 1], 16));
}
- if (BitUtil.check(reportMask, 19) && !values[index++].isEmpty()) {
- position.set("doors", Integer.parseInt(values[index - 1], 16));
+ if (BitUtil.check(reportMask, 19) && !v[index++].isEmpty()) {
+ position.set("doors", Integer.parseInt(v[index - 1], 16));
}
- if (BitUtil.check(reportMask, 20) && !values[index++].isEmpty()) {
- position.set("vehicleOverspeed", Double.parseDouble(values[index - 1]));
+ if (BitUtil.check(reportMask, 20) && !v[index++].isEmpty()) {
+ position.set("vehicleOverspeed", Double.parseDouble(v[index - 1]));
}
- if (BitUtil.check(reportMask, 21) && !values[index++].isEmpty()) {
- position.set("engineOverspeed", Double.parseDouble(values[index - 1]));
+ if (BitUtil.check(reportMask, 21) && !v[index++].isEmpty()) {
+ position.set("engineOverspeed", Double.parseDouble(v[index - 1]));
}
- if (BitUtil.check(reportMask, 29)) {
- reportMaskExt = Long.parseLong(values[index++], 16);
+ if ("GV350M".equals(model)) {
+ if (BitUtil.check(reportMask, 22)) {
+ index += 1; // impulse distance
+ }
+ if (BitUtil.check(reportMask, 23)) {
+ index += 1; // gross vehicle weight
+ }
+ if (BitUtil.check(reportMask, 24)) {
+ index += 1; // catalyst liquid level
+ }
+ } else if ("GV355CEU".equals(model)) {
+ if (BitUtil.check(reportMask, 22)) {
+ index += 1; // impulse distance
+ }
+ if (BitUtil.check(reportMask, 23)) {
+ index += 1; // engine cold starts
+ }
+ if (BitUtil.check(reportMask, 24)) {
+ index += 1; // engine all starts
+ }
+ if (BitUtil.check(reportMask, 25)) {
+ index += 1; // engine starts by ignition
+ }
+ if (BitUtil.check(reportMask, 26)) {
+ index += 1; // total engine cold running time
+ }
+ if (BitUtil.check(reportMask, 27)) {
+ index += 1; // handbrake applies during ride
+ }
+ if (BitUtil.check(reportMask, 28)) {
+ index += 1; // electric report mask
+ }
+ }
+ if (BitUtil.check(reportMask, 29) && !v[index++].isEmpty()) {
+ reportMaskExt = Long.parseLong(v[index - 1], 16);
}
- if (BitUtil.check(reportMaskExt, 0) && !values[index++].isEmpty()) {
- position.set("adBlueLevel", Integer.parseInt(values[index - 1]));
+ if (BitUtil.check(reportMaskExt, 0) && !v[index++].isEmpty()) {
+ position.set("adBlueLevel", Integer.parseInt(v[index - 1]));
}
- if (BitUtil.check(reportMaskExt, 1) && !values[index++].isEmpty()) {
- position.set("axleWeight1", Integer.parseInt(values[index - 1]));
+ if (BitUtil.check(reportMaskExt, 1) && !v[index++].isEmpty()) {
+ position.set("axleWeight1", Integer.parseInt(v[index - 1]));
}
- if (BitUtil.check(reportMaskExt, 2) && !values[index++].isEmpty()) {
- position.set("axleWeight3", Integer.parseInt(values[index - 1]));
+ if (BitUtil.check(reportMaskExt, 2) && !v[index++].isEmpty()) {
+ position.set("axleWeight3", Integer.parseInt(v[index - 1]));
}
- if (BitUtil.check(reportMaskExt, 3) && !values[index++].isEmpty()) {
- position.set("axleWeight4", Integer.parseInt(values[index - 1]));
+ if (BitUtil.check(reportMaskExt, 3) && !v[index++].isEmpty()) {
+ position.set("axleWeight4", Integer.parseInt(v[index - 1]));
}
if (BitUtil.check(reportMaskExt, 4)) {
index += 1; // tachograph overspeed
@@ -733,8 +596,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(reportMaskExt, 6)) {
index += 1; // tachograph direction
}
- if (BitUtil.check(reportMaskExt, 7) && !values[index++].isEmpty()) {
- position.set(Position.PREFIX_ADC + 1, Integer.parseInt(values[index - 1]) * 0.001);
+ if (BitUtil.check(reportMaskExt, 7) && !v[index++].isEmpty()) {
+ position.set(Position.PREFIX_ADC + 1, Integer.parseInt(v[index - 1]) * 0.001);
}
if (BitUtil.check(reportMaskExt, 8)) {
index += 1; // pedal breaking factor
@@ -757,20 +620,20 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(reportMaskExt, 14)) {
index += 1; // total brake application
}
- if (BitUtil.check(reportMaskExt, 15) && !values[index++].isEmpty()) {
- position.set("driver1Card", values[index - 1]);
+ if (BitUtil.check(reportMaskExt, 15) && !v[index++].isEmpty()) {
+ position.set("driver1Card", v[index - 1]);
}
- if (BitUtil.check(reportMaskExt, 16) && !values[index++].isEmpty()) {
- position.set("driver2Card", values[index - 1]);
+ if (BitUtil.check(reportMaskExt, 16) && !v[index++].isEmpty()) {
+ position.set("driver2Card", v[index - 1]);
}
- if (BitUtil.check(reportMaskExt, 17) && !values[index++].isEmpty()) {
- position.set("driver1Name", values[index - 1]);
+ if (BitUtil.check(reportMaskExt, 17) && !v[index++].isEmpty()) {
+ position.set("driver1Name", v[index - 1]);
}
- if (BitUtil.check(reportMaskExt, 18) && !values[index++].isEmpty()) {
- position.set("driver2Name", values[index - 1]);
+ if (BitUtil.check(reportMaskExt, 18) && !v[index++].isEmpty()) {
+ position.set("driver2Name", v[index - 1]);
}
- if (BitUtil.check(reportMaskExt, 19) && !values[index++].isEmpty()) {
- position.set("registration", values[index - 1]);
+ if (BitUtil.check(reportMaskExt, 19) && !v[index++].isEmpty()) {
+ position.set("registration", v[index - 1]);
}
if (BitUtil.check(reportMaskExt, 20)) {
index += 1; // expansion information
@@ -788,18 +651,18 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- if (BitUtil.check(reportMask, 30)) {
- while (values[index].isEmpty()) {
+ if (!"GV355CEU".equals(model) && BitUtil.check(reportMask, 30)) {
+ while (v[index].isEmpty()) {
index += 1;
}
- position.setValid(Integer.parseInt(values[index++]) > 0);
- if (!values[index].isEmpty()) {
- position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++])));
- position.setCourse(Integer.parseInt(values[index++]));
- position.setAltitude(Double.parseDouble(values[index++]));
- position.setLongitude(Double.parseDouble(values[index++]));
- position.setLatitude(Double.parseDouble(values[index++]));
- position.setTime(dateFormat.parse(values[index++]));
+ position.setValid(Integer.parseInt(v[index++]) > 0);
+ if (!v[index].isEmpty()) {
+ position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(v[index++])));
+ position.setCourse(Integer.parseInt(v[index++]));
+ position.setAltitude(Double.parseDouble(v[index++]));
+ position.setLongitude(Double.parseDouble(v[index++]));
+ position.setLatitude(Double.parseDouble(v[index++]));
+ position.setTime(dateFormat.parse(v[index++]));
} else {
index += 6; // no location
getLastLocation(position, null);
@@ -813,34 +676,79 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
index += 1; // reserved
}
+ index = v.length - 2;
if (ignoreFixTime) {
- position.setTime(dateFormat.parse(values[index]));
+ position.setTime(dateFormat.parse(v[index]));
} else {
- position.setDeviceTime(dateFormat.parse(values[index]));
+ position.setDeviceTime(dateFormat.parse(v[index]));
}
return position;
}
- private void decodeStatus(Position position, Parser parser) {
- if (parser.hasNext(3)) {
- int ignition = parser.nextHexInt();
- if (BitUtil.check(ignition, 4)) {
- position.set(Position.KEY_IGNITION, false);
- } else if (BitUtil.check(ignition, 5)) {
- position.set(Position.KEY_IGNITION, true);
- }
- int input = parser.nextHexInt();
- int output = parser.nextHexInt();
- position.set(Position.KEY_INPUT, input);
- position.set(Position.PREFIX_IN + 1, BitUtil.check(input, 1));
- position.set(Position.PREFIX_IN + 2, BitUtil.check(input, 2));
- position.set(Position.KEY_OUTPUT, output);
- position.set(Position.PREFIX_OUT + 1, BitUtil.check(output, 0));
- position.set(Position.PREFIX_OUT + 2, BitUtil.check(output, 1));
- }
+ private void decodeStatus(Position position, long value) {
+ long ignition = BitUtil.between(value, 2 * 8, 3 * 8);
+ if (BitUtil.check(ignition, 4)) {
+ position.set(Position.KEY_IGNITION, false);
+ } else if (BitUtil.check(ignition, 5)) {
+ position.set(Position.KEY_IGNITION, true);
+ }
+ long input = BitUtil.between(value, 8, 2 * 8);
+ long output = BitUtil.to(value, 8);
+ position.set(Position.KEY_INPUT, input);
+ position.set(Position.PREFIX_IN + 1, BitUtil.check(input, 1));
+ position.set(Position.PREFIX_IN + 2, BitUtil.check(input, 2));
+ position.set(Position.KEY_OUTPUT, output);
+ position.set(Position.PREFIX_OUT + 1, BitUtil.check(output, 0));
+ position.set(Position.PREFIX_OUT + 2, BitUtil.check(output, 1));
}
+ private static final Pattern PATTERN_FRI = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF):GT...,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("(?:([0-9A-Z]{17}),)?") // vin
+ .expression("[^,]*,") // device name
+ .number("(d+)?,") // power
+ .number("(d{1,2}),").optional() // report type
+ .number("d{1,2},").optional() // count
+ .number("d*,").optional() // reserved
+ .number("(d+),").optional() // battery
+ .expression("((?:")
+ .expression(PATTERN_LOCATION.pattern())
+ .expression(")+)")
+ .groupBegin()
+ .number("d{1,2},")
+ .number("(d{1,5})?,") // battery
+ .number("(d{1,3}),") // battery level
+ .number("[01],") // mode
+ .number("(?:[01])?,") // motion
+ .number("(-?d{1,2}.d)?,") // temperature
+ .or()
+ .number("(d{1,7}.d)?,") // odometer
+ .number("(d{5}:dd:dd)?,") // hour meter
+ .number("(x+)?,") // adc 1
+ .number("(x+)?,") // adc 2
+ .number("(d{1,3})?,") // battery
+ .number("(x{6})?,") // device status
+ .number("(d+)?,") // rpm
+ .number("(?:d+.?d*|Inf|NaN)?,") // fuel consumption
+ .number("(d+)?,") // fuel level
+ .or()
+ .number("(-?d),") // rssi
+ .number("(d{1,3}),") // battery
+ .or()
+ .number("(d{1,7}.d)?,").optional() // odometer
+ .number("(d{1,3})?,") // battery
+ .groupEnd()
+ .any()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeFri(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_FRI, sentence);
if (!parser.matches()) {
@@ -883,8 +791,10 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
}
if (parser.hasNext()) {
- position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
+ position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001);
}
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
+ position.set(Position.PREFIX_TEMP + 1, parser.nextDouble());
if (parser.hasNext()) {
position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
@@ -894,7 +804,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.PREFIX_ADC + 2, parser.next());
position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
- decodeStatus(position, parser);
+ if (parser.hasNext()) {
+ decodeStatus(position, parser.nextHexLong());
+ }
position.set(Position.KEY_RPM, parser.nextInt());
position.set(Position.KEY_FUEL_LEVEL, parser.nextInt());
@@ -921,109 +833,112 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return positions;
}
- private Object decodeEri(Channel channel, SocketAddress remoteAddress, String sentence) {
- Parser parser = new Parser(PATTERN_ERI, sentence);
- if (!parser.matches()) {
- return null;
- }
-
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ private Object decodeEri(Channel channel, SocketAddress remoteAddress, String[] v) throws ParseException {
+ int index = 0;
+ index += 1; // header
+ index += 1; // protocol version
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, v[index++]);
if (deviceSession == null) {
return null;
}
- long mask = parser.nextHexLong();
+ String model = getDeviceModel(deviceSession, v[index++]);
+ long mask = Long.parseLong(v[index++], 16);
+ Double power = v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001;
+ index += 1; // report type
+ int count = Integer.parseInt(v[index++]);
LinkedList<Position> positions = new LinkedList<>();
-
- Integer power = parser.nextInt();
-
- Parser itemParser = new Parser(PATTERN_LOCATION, parser.next());
- while (itemParser.find()) {
+ for (int i = 0; i < count; i++) {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
-
- decodeLocation(position, itemParser);
-
+ index = decodeLocation(position, model, v, index);
positions.add(position);
}
Position position = positions.getLast();
+ position.set(Position.KEY_POWER, power);
- skipLocation(parser);
-
- if (power != null) {
- position.set(Position.KEY_POWER, power * 0.001);
+ if (!model.startsWith("GL5")) {
+ position.set(Position.KEY_ODOMETER, v[index++].isEmpty() ? null : Double.parseDouble(v[index - 1]) * 1000);
+ position.set(Position.KEY_HOURS, parseHours(v[index++]));
+ position.set(Position.PREFIX_ADC + 1, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001);
+ }
+ if (model.startsWith("GV") && !model.startsWith("GV6")) {
+ position.set(Position.PREFIX_ADC + 2, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001);
}
- if (parser.hasNext(12)) {
-
- position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
- position.set(Position.KEY_HOURS, parseHours(parser.next()));
- position.set(Position.PREFIX_ADC + 1, parser.next());
- position.set(Position.PREFIX_ADC + 2, parser.next());
- position.set(Position.PREFIX_ADC + 3, parser.next());
- if (parser.hasNext(2)) {
- position.set(Position.KEY_INPUT, parser.nextHexInt());
- position.set(Position.KEY_OUTPUT, parser.nextHexInt());
- }
- if (parser.hasNext(4)) {
- position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
- decodeStatus(position, parser);
+ position.set(Position.KEY_BATTERY_LEVEL, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]));
+ if (model.startsWith("GL5")) {
+ index += 1; // mode selection
+ position.set(Position.KEY_MOTION, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) > 0);
+ } else {
+ if (!v[index++].isEmpty()) {
+ decodeStatus(position, Long.parseLong(v[index - 1]));
}
+ index += 1; // reserved / uart device type
+ }
- int index = 0;
- String[] data = parser.next().split(",");
-
- index += 1; // device type
-
- if (BitUtil.check(mask, 0)) {
- index += 1; // digital fuel sensor data
- }
+ if (BitUtil.check(mask, 0)) {
+ position.set(Position.KEY_FUEL_LEVEL, Integer.parseInt(v[index++], 16));
+ }
- if (BitUtil.check(mask, 1)) {
- int deviceCount = Integer.parseInt(data[index++]);
- for (int i = 1; i <= deviceCount; i++) {
- index += 1; // id
- index += 1; // type
- if (!data[index++].isEmpty()) {
- position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(data[index - 1], 16) * 0.0625);
- }
+ if (BitUtil.check(mask, 1)) {
+ int deviceCount = Integer.parseInt(v[index++]);
+ for (int i = 1; i <= deviceCount; i++) {
+ index += 1; // id
+ index += 1; // type
+ if (!v[index++].isEmpty()) {
+ position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(v[index - 1], 16) * 0.0625);
}
}
+ }
- if (BitUtil.check(mask, 2)) {
- index += 1; // can data
- }
+ if (BitUtil.check(mask, 2)) {
+ index += 1; // can data
+ }
- if (BitUtil.check(mask, 3) || BitUtil.check(mask, 4)) {
- int deviceCount = Integer.parseInt(data[index++]);
- for (int i = 1; i <= deviceCount; i++) {
- index += 1; // type
- if (BitUtil.check(mask, 3)) {
- position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(data[index++]));
- }
- if (BitUtil.check(mask, 4)) {
- index += 1; // volume
- }
+ if (BitUtil.check(mask, 3) || BitUtil.check(mask, 4)) {
+ int deviceCount = Integer.parseInt(v[index++]);
+ for (int i = 1; i <= deviceCount; i++) {
+ index += 1; // type
+ if (BitUtil.check(mask, 3)) {
+ position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(v[index++]));
+ }
+ if (BitUtil.check(mask, 4)) {
+ index += 1; // volume
}
}
-
}
- if (parser.hasNext()) {
- position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
- }
-
- decodeDeviceTime(position, parser);
+ Date time = dateFormat.parse(v[v.length - 2]);
if (ignoreFixTime) {
+ position.setTime(time);
positions.clear();
positions.add(position);
+ } else {
+ position.setDeviceTime(time);
}
return positions;
}
+ private static final Pattern PATTERN_IGN = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF):GTIG[NF],")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("d+,") // ignition off duration
+ .expression(PATTERN_LOCATION.pattern())
+ .number("(d{5}:dd:dd)?,") // hour meter
+ .number("(d{1,7}.d)?,") // odometer
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeIgn(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_IGN, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1042,6 +957,21 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_LSW = new PatternBuilder()
+ .text("+RESP:").expression("GT[LT]SW,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("[01],") // type
+ .number("([01]),") // state
+ .expression(PATTERN_LOCATION.pattern())
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeLsw(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_LSW, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1058,6 +988,24 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_IDA = new PatternBuilder()
+ .text("+RESP:GTIDA,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,,") // device name
+ .number("([^,]+),") // rfid
+ .expression("[01],") // report type
+ .number("1,") // count
+ .expression(PATTERN_LOCATION.pattern())
+ .number("(d+.d),") // odometer
+ .text(",,,,")
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeIda(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_IDA, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1076,6 +1024,21 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_WIF = new PatternBuilder()
+ .text("+RESP:GTWIF,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("(d+),") // count
+ .number("((?:x{12},-?d+,,,,)+),,,,") // wifi
+ .number("(d{1,3}),") // battery
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeWif(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_WIF, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1102,6 +1065,19 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_GSM = new PatternBuilder()
+ .text("+RESP:GTGSM,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("(?:STR|CTN|NMR|RTL),") // fix type
+ .expression("(.*)") // cells
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeGsm(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_GSM, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1128,6 +1104,18 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_PNA = new PatternBuilder()
+ .text("+RESP:GT").expression("P[NF]A,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodePna(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_PNA, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1142,6 +1130,22 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_DAR = new PatternBuilder()
+ .text("+RESP:GTDAR,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("(d),") // warning type
+ .number("(d{1,2}),,,") // fatigue degree
+ .expression(PATTERN_LOCATION.pattern())
+ .any()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeDar(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_DAR, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1165,6 +1169,204 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_DTT = new PatternBuilder()
+ .text("+RESP:GTDTT,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,,,") // device name
+ .number("d,") // data type
+ .number("d+,") // data length
+ .number("(x+),") // data
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
+ private Object decodeDtt(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_DTT, sentence);
+ Position position = initPosition(parser, channel, remoteAddress);
+ if (position == null) {
+ return null;
+ }
+
+ getLastLocation(position, null);
+
+ String data = Unpooled.wrappedBuffer(DataConverter.parseHex(parser.next()))
+ .toString(StandardCharsets.US_ASCII);
+ if (data.contains("COMB")) {
+ position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(data.split(",")[2]));
+ } else {
+ position.set(Position.KEY_RESULT, data);
+ }
+
+ decodeDeviceTime(position, parser);
+
+ return position;
+ }
+
+ private static final Pattern PATTERN_BAA = new PatternBuilder()
+ .text("+RESP:GTBAA,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("x+,") // index
+ .number("d,") // accessory type
+ .number("d,") // accessory model
+ .number("x+,") // alarm type
+ .number("(x{4}),") // append mask
+ .expression("((?:[^,]+,){0,6})") // accessory optionals
+ .expression(PATTERN_LOCATION.pattern())
+ .any()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
+ private Object decodeBaa(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_BAA, sentence);
+ Position position = initPosition(parser, channel, remoteAddress);
+ if (position == null) {
+ return null;
+ }
+
+ int mask = parser.nextHexInt();
+ String[] values = parser.next().split(",");
+ int index = 0;
+ if (BitUtil.check(mask, 0)) {
+ position.set("accessoryName", values[index++]);
+ }
+ if (BitUtil.check(mask, 1)) {
+ position.set("accessoryMac", values[index++]);
+ }
+ if (BitUtil.check(mask, 2)) {
+ position.set("accessoryStatus", Integer.parseInt(values[index++]));
+ }
+ if (BitUtil.check(mask, 3)) {
+ position.set("accessoryVoltage", Integer.parseInt(values[index++]) * 0.001);
+ }
+ if (BitUtil.check(mask, 4)) {
+ position.set("accessoryTemp", Integer.parseInt(values[index++]));
+ }
+ if (BitUtil.check(mask, 5)) {
+ position.set("accessoryHumidity", Integer.parseInt(values[index]));
+ }
+
+ decodeLocation(position, parser);
+
+ decodeDeviceTime(position, parser);
+
+ return position;
+ }
+
+ private static final Pattern PATTERN_BID = new PatternBuilder()
+ .text("+RESP:GTBID,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("d,") // count
+ .number("d,") // accessory model
+ .number("(x{4}),") // append mask
+ .expression("((?:[^,]+,){0,2})") // accessory optionals
+ .expression(PATTERN_LOCATION.pattern())
+ .any()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
+ private Object decodeBid(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_BID, sentence);
+ Position position = initPosition(parser, channel, remoteAddress);
+ if (position == null) {
+ return null;
+ }
+
+ int mask = parser.nextHexInt();
+ String[] values = parser.next().split(",");
+ int index = 0;
+ if (BitUtil.check(mask, 1)) {
+ position.set("accessoryMac", values[index++]);
+ }
+ if (BitUtil.check(mask, 3)) {
+ position.set("accessoryVoltage", Integer.parseInt(values[index]) * 0.001);
+ }
+
+ decodeLocation(position, parser);
+
+ decodeDeviceTime(position, parser);
+
+ return position;
+ }
+
+ private static final Pattern PATTERN_LSA = new PatternBuilder()
+ .text("+RESP:GTLSA,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("d,") // event state 1
+ .number("d,") // event state 2
+ .number("d+,") // number
+ .expression(PATTERN_LOCATION.pattern())
+ .number("d+,") // bit error rate
+ .number("(d),") // light level
+ .number("(d+),") // battery level
+ .number("[01],") // mode selection
+ .number("[01]?,") // movement status
+ .number("(-?d+.d)?,") // temperature
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
+ private Object decodeLsa(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_LSA, sentence);
+ Position position = initPosition(parser, channel, remoteAddress);
+ if (position == null) {
+ return null;
+ }
+
+ decodeLocation(position, parser);
+
+ position.set("lightLevel", parser.nextInt());
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
+ position.set(Position.PREFIX_TEMP + 1, parser.nextDouble());
+
+ decodeDeviceTime(position, parser);
+
+ return position;
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF):GT...,")
+ .expression("(?:.{6}|.{10})?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("d*,")
+ .number("(x{1,2}),") // report type
+ .number("d{1,2},") // count
+ .number("d*,").optional() // reserved
+ .expression(PATTERN_LOCATION.pattern())
+ .groupBegin()
+ .number("(?:(d{1,7}.d)|0)?,").optional() // odometer
+ .number("(d{1,3})?,") // battery
+ .or()
+ .number("(d{1,7}.d)?,") // odometer
+ .groupEnd()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)") // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeOther(Channel channel, SocketAddress remoteAddress, String sentence, String type) {
Parser parser = new Parser(PATTERN, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1215,6 +1417,38 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_BASIC = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF)").text(":")
+ .expression("GT...,")
+ .expression("[^,]+,").optional() // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .any()
+ .text(",")
+ .number("(d{1,2}),") // hdop
+ .groupBegin()
+ .number("(d{1,3}.d),") // speed
+ .number("(d{1,3}),") // course
+ .number("(-?d{1,5}.d),") // altitude
+ .number("(-?d{1,3}.d{6}),") // longitude
+ .number("(-?d{1,2}.d{6}),") // latitude
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)") // time (hhmmss)
+ .text(",")
+ .or()
+ .text(",,,,,,")
+ .groupEnd()
+ .number("(d+),") // mcc
+ .number("(d+),") // mnc
+ .number("(x+),") // lac
+ .number("(x+),").optional(4) // cell
+ .any()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeBasic(Channel channel, SocketAddress remoteAddress, String sentence, String type) {
Parser parser = new Parser(PATTERN_BASIC, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1299,17 +1533,19 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String sentence = ((ByteBuf) msg).toString(StandardCharsets.US_ASCII);
+ String sentence = ((ByteBuf) msg).toString(StandardCharsets.US_ASCII).replaceAll("\\$$", "");
int typeIndex = sentence.indexOf(":GT");
if (typeIndex < 0) {
return null;
}
+ String[] values = sentence.split(",");
+
Object result;
String type = sentence.substring(typeIndex + 3, typeIndex + 6);
if (sentence.startsWith("+ACK")) {
- result = decodeAck(channel, remoteAddress, sentence, type);
+ result = decodeAck(channel, remoteAddress, values);
} else {
switch (type) {
case "INF":
@@ -1319,7 +1555,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
result = decodeObd(channel, remoteAddress, sentence);
break;
case "CAN":
- result = decodeCan(channel, remoteAddress, sentence);
+ result = decodeCan(channel, remoteAddress, values);
break;
case "CTN":
case "FRI":
@@ -1330,7 +1566,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
result = decodeFri(channel, remoteAddress, sentence);
break;
case "ERI":
- result = decodeEri(channel, remoteAddress, sentence);
+ result = decodeEri(channel, remoteAddress, values);
break;
case "IGN":
case "IGF":
@@ -1359,6 +1595,18 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
case "DAR":
result = decodeDar(channel, remoteAddress, sentence);
break;
+ case "DTT":
+ result = decodeDtt(channel, remoteAddress, sentence);
+ break;
+ case "BAA":
+ result = decodeBaa(channel, remoteAddress, sentence);
+ break;
+ case "BID":
+ result = decodeBid(channel, remoteAddress, sentence);
+ break;
+ case "LSA":
+ result = decodeLsa(channel, remoteAddress, sentence);
+ break;
default:
result = decodeOther(channel, remoteAddress, sentence, type);
break;
@@ -1380,13 +1628,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
}
if (channel != null && getConfig().getBoolean(Keys.PROTOCOL_ACK.withPrefix(getProtocolName()))) {
- String checksum;
- if (sentence.endsWith("$")) {
- checksum = sentence.substring(sentence.length() - 1 - 4, sentence.length() - 1);
- } else {
- checksum = sentence.substring(sentence.length() - 4);
- }
- channel.writeAndFlush(new NetworkMessage("+SACK:" + checksum + "$", remoteAddress));
+ channel.writeAndFlush(new NetworkMessage("+SACK:" + values[values.length - 1] + "$", remoteAddress));
}
return result;