diff options
Diffstat (limited to 'src/main/java/org/traccar/protocol')
24 files changed, 865 insertions, 203 deletions
diff --git a/src/main/java/org/traccar/protocol/AdmProtocolDecoder.java b/src/main/java/org/traccar/protocol/AdmProtocolDecoder.java index 31064286e..7e3478704 100644 --- a/src/main/java/org/traccar/protocol/AdmProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/AdmProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2021 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. @@ -97,7 +97,7 @@ public class AdmProtocolDecoder extends BaseProtocolDecoder { if (BitUtil.check(type, 5)) { for (int i = 1; i <= 3; i++) { - buf.readUnsignedShortLE(); // fuel level + position.set("fuel" + i, buf.readUnsignedShortLE()); } for (int i = 1; i <= 3; i++) { position.set(Position.PREFIX_TEMP + i, buf.readUnsignedByte()); diff --git a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java index ff7ef6c4a..186b81470 100644 --- a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2021 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; @@ -24,6 +25,8 @@ import org.traccar.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.DateBuilder; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; @@ -115,6 +118,89 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { return result; } + private void decodeBeaconData(Position position, int mode, int mask, ByteBuf data) { + int i = 1; + while (data.isReadable()) { + if (BitUtil.check(mask, 7)) { + position.set("tag" + i + "Id", ByteBufUtil.hexDump(data.readSlice(6))); + } + switch (mode) { + case 1: + if (BitUtil.check(mask, 6)) { + data.readUnsignedShort(); // major + } + if (BitUtil.check(mask, 5)) { + data.readUnsignedShort(); // minor + } + if (BitUtil.check(mask, 4)) { + data.readUnsignedByte(); // tx power + } + if (BitUtil.check(mask, 3)) { + position.set("tag" + i + "Rssi", data.readUnsignedByte()); + } + break; + case 2: + if (BitUtil.check(mask, 6)) { + data.readUnsignedShort(); // battery voltage + } + if (BitUtil.check(mask, 5)) { + position.set("tag" + i + "Temp", data.readUnsignedShort()); + } + if (BitUtil.check(mask, 4)) { + data.readUnsignedByte(); // tx power + } + if (BitUtil.check(mask, 3)) { + position.set("tag" + i + "Rssi", data.readUnsignedByte()); + } + break; + case 3: + if (BitUtil.check(mask, 6)) { + position.set("tag" + i + "Humidity", data.readUnsignedShort()); + } + if (BitUtil.check(mask, 5)) { + position.set("tag" + i + "Temp", data.readUnsignedShort()); + } + if (BitUtil.check(mask, 3)) { + position.set("tag" + i + "Rssi", data.readUnsignedByte()); + } + if (BitUtil.check(mask, 2)) { + data.readUnsignedShort(); + } + break; + case 4: + if (BitUtil.check(mask, 6)) { + int hardwareId = data.readUnsignedByte(); + if (BitUtil.check(mask, 5)) { + switch (hardwareId) { + case 1: + case 4: + data.skipBytes(11); // fuel + break; + case 2: + data.skipBytes(2); // temperature + break; + case 3: + data.skipBytes(6); // temperature and luminosity + break; + case 5: + data.skipBytes(10); // temperature, humidity, luminosity and pressure + break; + default: + break; + } + } + } + if (BitUtil.check(mask, 4)) { + data.skipBytes(9); // name + } + break; + default: + break; + } + i += 1; + } + } + private void readTextCustomData(Position position, String data, String form) { CellTower cellTower = new CellTower(); String[] keys = form.substring(1).split("%"); @@ -208,6 +294,12 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { case "MT": position.set(Position.KEY_MOTION, Integer.parseInt(values[i]) > 0); break; + case "BC": + String[] beaconValues = values[i].split(":"); + decodeBeaconData( + position, Integer.parseInt(beaconValues[0]), Integer.parseInt(beaconValues[1]), + Unpooled.wrappedBuffer(DataConverter.parseHex(beaconValues[2]))); + break; default: break; } diff --git a/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java b/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java index 75fdc3253..96b06557a 100644 --- a/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2021 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. @@ -197,7 +197,8 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder { } else if (fieldId == 6) { while (buf.readerIndex() < fieldEnd) { - switch (buf.readUnsignedByte()) { + int number = buf.readUnsignedByte(); + switch (number) { case 1: position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); break; @@ -214,7 +215,7 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder { position.set("solarPower", buf.readUnsignedShortLE() * 0.001); break; default: - buf.readUnsignedShortLE(); // other + position.set(Position.PREFIX_IO + number, buf.readUnsignedShortLE()); break; } } diff --git a/src/main/java/org/traccar/protocol/DolphinProtocolDecoder.java b/src/main/java/org/traccar/protocol/DolphinProtocolDecoder.java index 56d9314b2..e882c2378 100644 --- a/src/main/java/org/traccar/protocol/DolphinProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/DolphinProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2020 - 2021 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,11 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; @@ -43,7 +45,7 @@ public class DolphinProtocolDecoder extends BaseProtocolDecoder { ByteBuf buf = (ByteBuf) msg; buf.readUnsignedShort(); // header - buf.readUnsignedIntLE(); // index + int index = (int) buf.readUnsignedIntLE(); buf.readUnsignedShort(); // version buf.readUnsignedShort(); // flags int type = buf.readUnsignedShortLE(); @@ -61,6 +63,24 @@ public class DolphinProtocolDecoder extends BaseProtocolDecoder { DolphinMessages.DataPackRequest message = DolphinMessages.DataPackRequest.parseFrom( ByteBufUtil.getBytes(buf, buf.readerIndex(), length, false)); + if (channel != null) { + byte[] responseData = DolphinMessages.DataPackResponse.newBuilder() + .setResponse(DolphinMessages.DataPackResponseCode.DataPack_OK) + .build() + .toByteArray(); + + ByteBuf response = Unpooled.buffer(); + response.writeShort(0xABAB); // header + response.writeIntLE(index); + response.writeShort(0); // flags + response.writeShortLE(DolphinMessages.MessageType.DataPack_Response.getNumber()); + response.writeIntLE(responseData.length); + response.writeIntLE(0); // reserved + response.writeBytes(responseData); + + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + List<Position> positions = new LinkedList<>(); for (int i = 0; i < message.getPointsCount(); i++) { diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java index fe42a44d7..9bed63266 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2021 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. @@ -95,6 +95,16 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { .number("(d+),") // size .compile(); + private static final Pattern PATTERN_RESULT = new PatternBuilder() + .text("$$") + .number("d+,") // length + .number("(d+),") // imei + .any() + .expression(",([A-Z]+)") // result + .text("*") + .number("xx") + .compile(); + private void requestPhoto(Channel channel, SocketAddress socketAddress, String imei, String file) { if (channel != null) { String content = "1,D06," + file + "," + photo.writerIndex() + "," + Math.min(1024, photo.writableBytes()); @@ -203,6 +213,27 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { return position; } + private Object decodeResult( + Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_RESULT, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_RESULT, parser.next()); + + return position; + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -213,7 +244,12 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { typeIndex = buf.indexOf(typeIndex, buf.writerIndex(), (byte) ',') + 1; String type = buf.toString(typeIndex, 3, StandardCharsets.US_ASCII); - if (type.equals("D05")) { + if (type.startsWith("B")) { + + return decodeResult(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII)); + + } else if (type.equals("D05")) { + String sentence = buf.toString(StandardCharsets.US_ASCII); Parser parser = new Parser(PATTERN_PHOTO, sentence); if (parser.matches()) { @@ -223,7 +259,9 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { photo = Unpooled.buffer(length); requestPhoto(channel, remoteAddress, imei, photoId); } + } else if (type.equals("D06")) { + if (photo == null) { return null; } @@ -251,9 +289,11 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { return position; } } + } else { - String sentence = buf.toString(StandardCharsets.US_ASCII); - return decodeLocation(channel, remoteAddress, sentence); + + return decodeLocation(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII)); + } return null; diff --git a/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java b/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java index b6d7f4e45..aded35823 100644 --- a/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2021 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. @@ -75,9 +75,9 @@ public class FreematicsProtocolDecoder extends BaseProtocolDecoder { } private Object decodePosition( - Channel channel, SocketAddress remoteAddress, String sentence) throws Exception { + Channel channel, SocketAddress remoteAddress, String sentence, String id) { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); if (deviceSession == null) { return null; } @@ -88,94 +88,104 @@ public class FreematicsProtocolDecoder extends BaseProtocolDecoder { for (String pair : sentence.split(",")) { String[] data = pair.split("[=:]"); - int key = Integer.parseInt(data[0], 16); + int key; + try { + key = Integer.parseInt(data[0], 16); + } catch (NumberFormatException e) { + continue; + } String value = data[1]; - switch (key) { - case 0x0: - if (position != null) { - position.setTime(dateBuilder.getDate()); - positions.add(position); - } - position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.setValid(true); - dateBuilder = new DateBuilder(new Date()); - break; - case 0x11: - value = ("000000" + value).substring(value.length()); - dateBuilder.setDateReverse( - Integer.parseInt(value.substring(0, 2)), - Integer.parseInt(value.substring(2, 4)), - Integer.parseInt(value.substring(4))); - break; - case 0x10: - value = ("00000000" + value).substring(value.length()); - dateBuilder.setTime( - Integer.parseInt(value.substring(0, 2)), - Integer.parseInt(value.substring(2, 4)), - Integer.parseInt(value.substring(4, 6)), - Integer.parseInt(value.substring(6)) * 10); - break; - case 0xA: - position.setLatitude(Double.parseDouble(value)); - break; - case 0xB: - position.setLongitude(Double.parseDouble(value)); - break; - case 0xC: - position.setAltitude(Double.parseDouble(value)); - break; - case 0xD: - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(value))); - break; - case 0xE: - position.setCourse(Integer.parseInt(value)); - break; - case 0xF: - position.set(Position.KEY_SATELLITES, Integer.parseInt(value)); - break; - case 0x12: - position.set(Position.KEY_HDOP, Integer.parseInt(value)); - break; - case 0x20: - position.set(Position.KEY_ACCELERATION, value); - break; - case 0x24: - position.set(Position.KEY_BATTERY, Integer.parseInt(value) * 0.01); - break; - case 0x81: - position.set(Position.KEY_RSSI, Integer.parseInt(value)); - break; - case 0x82: - position.set(Position.KEY_DEVICE_TEMP, Integer.parseInt(value) * 0.1); - break; - case 0x104: - position.set(Position.KEY_ENGINE_LOAD, Integer.parseInt(value)); - break; - case 0x105: - position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(value)); - break; - case 0x10c: - position.set(Position.KEY_RPM, Integer.parseInt(value)); - break; - case 0x10d: - position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(Integer.parseInt(value))); - break; - case 0x111: - position.set(Position.KEY_THROTTLE, Integer.parseInt(value)); - break; - default: - position.set(Position.PREFIX_IO + key, value); - break; + if (key == 0x0) { + if (position != null) { + position.setTime(dateBuilder.getDate()); + positions.add(position); + } + position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + dateBuilder = new DateBuilder(new Date()); + } else if (position != null) { + switch (key) { + case 0x11: + value = ("000000" + value).substring(value.length()); + dateBuilder.setDateReverse( + Integer.parseInt(value.substring(0, 2)), + Integer.parseInt(value.substring(2, 4)), + Integer.parseInt(value.substring(4))); + break; + case 0x10: + value = ("00000000" + value).substring(value.length()); + dateBuilder.setTime( + Integer.parseInt(value.substring(0, 2)), + Integer.parseInt(value.substring(2, 4)), + Integer.parseInt(value.substring(4, 6)), + Integer.parseInt(value.substring(6)) * 10); + break; + case 0xA: + position.setValid(true); + position.setLatitude(Double.parseDouble(value)); + break; + case 0xB: + position.setValid(true); + position.setLongitude(Double.parseDouble(value)); + break; + case 0xC: + position.setAltitude(Double.parseDouble(value)); + break; + case 0xD: + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(value))); + break; + case 0xE: + position.setCourse(Integer.parseInt(value)); + break; + case 0xF: + position.set(Position.KEY_SATELLITES, Integer.parseInt(value)); + break; + case 0x12: + position.set(Position.KEY_HDOP, Integer.parseInt(value)); + break; + case 0x20: + position.set(Position.KEY_ACCELERATION, value); + break; + case 0x24: + position.set(Position.KEY_BATTERY, Integer.parseInt(value) * 0.01); + break; + case 0x81: + position.set(Position.KEY_RSSI, Integer.parseInt(value)); + break; + case 0x82: + position.set(Position.KEY_DEVICE_TEMP, Integer.parseInt(value) * 0.1); + break; + case 0x104: + position.set(Position.KEY_ENGINE_LOAD, Integer.parseInt(value)); + break; + case 0x105: + position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(value)); + break; + case 0x10c: + position.set(Position.KEY_RPM, Integer.parseInt(value)); + break; + case 0x10d: + position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(Integer.parseInt(value))); + break; + case 0x111: + position.set(Position.KEY_THROTTLE, Integer.parseInt(value)); + break; + default: + position.set(Position.PREFIX_IO + key, value); + break; + } } } if (position != null) { + if (!position.getValid()) { + getLastLocation(position, null); + } position.setTime(dateBuilder.getDate()); positions.add(position); } - return positions; + return positions.isEmpty() ? null : positions; } @Override @@ -187,12 +197,13 @@ public class FreematicsProtocolDecoder extends BaseProtocolDecoder { int endIndex = sentence.indexOf('*'); if (startIndex > 0 && endIndex > 0) { + String id = sentence.substring(0, startIndex); sentence = sentence.substring(startIndex + 1, endIndex); if (sentence.startsWith("EV")) { return decodeEvent(channel, remoteAddress, sentence); } else { - return decodePosition(channel, remoteAddress, sentence); + return decodePosition(channel, remoteAddress, sentence, id); } } diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index d438aa33d..126656361 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 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2021 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. @@ -75,7 +75,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .expression("(?:[0-9Ff]{20})?,") // iccid .number("(d{1,2}),") // rssi .number("d{1,2},") - .expression("[01],") // external power + .expression("[01]{1,2},") // external power .number("([d.]+)?,") // odometer or external power .number("d*,") // backup battery or lightness .number("(d+.d+),") // battery @@ -97,6 +97,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .number("(xx)?,") // digital output .number("[-+]dddd,") // timezone .expression("[01],") // daylight saving + .or() + .any() .groupEnd() .number("(dddd)(dd)(dd)") // date (yyyymmdd) .number("(dd)(dd)(dd),") // time (hhmmss) @@ -237,8 +239,14 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .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*,,") @@ -920,15 +928,21 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_POWER, power * 0.001); } - if (parser.hasNext(9)) { + 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.KEY_BATTERY_LEVEL, parser.nextInt()); - - decodeStatus(position, parser); + 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); + } int index = 0; String[] data = parser.next().split(","); diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index c5e8809e3..b7d6d2595 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -838,7 +838,9 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedShort(); // satellites buf.readUnsignedByte(); // alarm buf.readUnsignedByte(); // language - buf.readUnsignedByte(); // battery + + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + buf.readUnsignedByte(); // working mode buf.readUnsignedShort(); // working voltage buf.readUnsignedByte(); // reserved diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java index 3ad70bdca..2e1ddf5f2 100644 --- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2021 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. @@ -234,8 +234,14 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder { int length = buf.readUnsignedShort() - 4; switch (subtype) { case 0x0001: - position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte() - 40); - position.set(Position.KEY_RPM, buf.readUnsignedShort()); + int coolantTemperature = buf.readUnsignedByte() - 40; + if (coolantTemperature <= 215) { + position.set(Position.KEY_COOLANT_TEMP, coolantTemperature); + } + int rpm = buf.readUnsignedShort(); + if (rpm <= 65535) { + position.set(Position.KEY_RPM, rpm); + } position.set("averageSpeed", buf.readUnsignedByte()); buf.readUnsignedShort(); // interval fuel consumption position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 0.01); diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index a3d16cb62..675a08aef 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2021 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. @@ -45,6 +45,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_GENERAL_RESPONSE = 0x8001; public static final int MSG_GENERAL_RESPONSE_2 = 0x4401; + public static final int MSG_HEARTBEAT = 0x0002; public static final int MSG_TERMINAL_REGISTER = 0x0100; public static final int MSG_TERMINAL_REGISTER_RESPONSE = 0x8100; public static final int MSG_TERMINAL_CONTROL = 0x8105; @@ -171,7 +172,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { formatMessage(MSG_TERMINAL_REGISTER_RESPONSE, id, false, response), remoteAddress)); } - } else if (type == MSG_TERMINAL_AUTH) { + } else if (type == MSG_TERMINAL_AUTH || type == MSG_HEARTBEAT) { sendGeneralResponse(channel, remoteAddress, id, type, index); @@ -334,24 +335,36 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set("cover", BitUtil.check(deviceStatus, 3)); break; case 0xEB: - while (buf.readerIndex() < endIndex) { - int extendedLength = buf.readUnsignedShort(); - int extendedType = buf.readUnsignedShort(); - switch (extendedType) { - case 0x0001: - position.set("fuel1", buf.readUnsignedShort() * 0.1); - buf.readUnsignedByte(); // unused - break; - case 0x0023: - position.set("fuel2", Double.parseDouble( - buf.readCharSequence(6, StandardCharsets.US_ASCII).toString())); - break; - case 0x00CE: - position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); - break; - default: - buf.skipBytes(extendedLength - 2); - break; + if (buf.getUnsignedShort(buf.readerIndex()) > 200) { + Network network = new Network(); + int mcc = buf.readUnsignedShort(); + int mnc = buf.readUnsignedByte(); + while (buf.readerIndex() < endIndex) { + network.addCellTower(CellTower.from( + mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedShort(), + buf.readUnsignedByte())); + } + position.setNetwork(network); + } else { + while (buf.readerIndex() < endIndex) { + int extendedLength = buf.readUnsignedShort(); + int extendedType = buf.readUnsignedShort(); + switch (extendedType) { + case 0x0001: + position.set("fuel1", buf.readUnsignedShort() * 0.1); + buf.readUnsignedByte(); // unused + break; + case 0x0023: + position.set("fuel2", Double.parseDouble( + buf.readCharSequence(6, StandardCharsets.US_ASCII).toString())); + break; + case 0x00CE: + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); + break; + default: + buf.skipBytes(extendedLength - 2); + break; + } } } break; diff --git a/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java b/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java index bbb63fb65..9c94ffd4b 100644 --- a/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java @@ -84,6 +84,156 @@ public class IotmProtocolDecoder extends BaseProtocolDecoder { } } + private void decodeSensor(Position position, ByteBuf record, int sensorType, int sensorId) { + String key; + switch (sensorId) { + case 0x0002: + position.set(Position.KEY_MOTION, sensorType > 0); + break; + case 0x0008: + case 0x009B: + if (sensorType > 0) { + position.set(Position.KEY_ALARM, Position.ALARM_JAMMING); + } + break; + case 0x0010: + case 0x0011: + case 0x0012: + case 0x0013: + case 0x0014: + case 0x0015: + key = Position.PREFIX_IN + (sensorId - 0x0010 + 2); + position.set(key, sensorType > 0); + break; + case 0x0062: + position.set("doorFL", sensorType > 0); + break; + case 0x0063: + position.set("doorFR", sensorType > 0); + break; + case 0x0064: + position.set("doorRL", sensorType > 0); + break; + case 0x0065: + position.set("doorRR", sensorType > 0); + break; + case 0x001E: + position.set("buttonPresent", sensorType > 0); + break; + case 0x006D: + position.set(Position.KEY_IGNITION, sensorType > 0); + break; + case 0x008B: + position.set("handBrake", sensorType > 0); + break; + case 0x008C: + position.set("footBrake", sensorType > 0); + break; + case 0x0094: + case 0x0095: + case 0x0096: + key = Position.PREFIX_OUT + (sensorId - 0x0094 + 1); + position.set(key, sensorType > 0); + break; + case 0x009A: + position.set(Position.PREFIX_OUT + 4, sensorType > 0); + break; + case 0x2000: + position.set(Position.KEY_OBD_SPEED, record.readUnsignedByte()); + break; + case 0x2001: + position.set(Position.KEY_SATELLITES, record.readUnsignedByte()); + break; + case 0x2006: + position.set(Position.KEY_THROTTLE, record.readUnsignedByte()); + break; + case 0x2007: + position.set(Position.KEY_FUEL_LEVEL, record.readUnsignedByte()); + break; + case 0x2008: + position.set(Position.KEY_COOLANT_TEMP, record.readUnsignedByte()); + break; + case 0x2009: + position.set("fuel2", record.readUnsignedByte()); + break; + case 0x200A: + position.set(Position.KEY_ENGINE_LOAD, record.readUnsignedByte()); + break; + case 0x2041: + position.set(Position.KEY_BATTERY_LEVEL, record.readUnsignedByte()); + break; + case 0x3000: + position.set(Position.KEY_POWER, record.readUnsignedShortLE() * 0.001); + break; + case 0x3001: + case 0x3002: + case 0x3003: + key = Position.PREFIX_ADC + (0x3003 - sensorId + 3); + position.set(key, record.readUnsignedShortLE() * 0.001); + break; + case 0x3004: + position.set(Position.KEY_BATTERY, record.readUnsignedShortLE() * 0.001); + break; + case 0x300C: + position.set(Position.KEY_RPM, record.readUnsignedShortLE()); + break; + case 0x3021: + position.set(Position.KEY_FUEL_CONSUMPTION, record.readUnsignedShortLE() * 0.05); + break; + case 0x3037: + position.set("cargoWeight", record.readUnsignedShortLE() * 2); + break; + case 0x4001: + position.set(Position.KEY_FUEL_USED, record.readUnsignedIntLE()); + break; + case 0x4002: + position.set(Position.KEY_HOURS, record.readUnsignedIntLE()); + break; + case 0x4003: + position.set(Position.KEY_ODOMETER, record.readUnsignedIntLE() * 5); + break; + case 0x4063: + position.set(Position.KEY_AXLE_WEIGHT, record.readUnsignedIntLE()); + break; + case 0x5000: + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(record.readLongLE())); + break; + case 0x5004: + case 0x5005: + case 0x5006: + case 0x5007: + key = Position.PREFIX_TEMP + (sensorId - 0x5004 + 1); + position.set(key, record.readLongLE()); + break; + case 0x500D: + position.set("trailerId", String.valueOf(record.readLongLE())); + break; + case 0xA000: + position.set(Position.KEY_DEVICE_TEMP, record.readFloatLE()); + break; + case 0xA001: + position.set(Position.KEY_ACCELERATION, record.readFloatLE()); + break; + case 0xA002: + position.set("cornering", record.readFloatLE()); + break; + case 0xA017: + case 0xA018: + case 0xA019: + case 0xA01A: + key = Position.PREFIX_TEMP + (sensorId - 0xA017 + 1); + position.set(key, record.readFloatLE()); + break; + case 0xB002: + position.set(Position.KEY_OBD_ODOMETER, record.readDoubleLE()); + break; + default: + key = Position.PREFIX_IO + sensorId; + position.getAttributes().put(key, readValue(record, sensorType)); + break; + } + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -163,62 +313,7 @@ public class IotmProtocolDecoder extends BaseProtocolDecoder { continue; } - String key; - switch (sensorId) { - case 0x0008: - if (sensorType > 0) { - position.set(Position.KEY_ALARM, Position.ALARM_JAMMING); - } - break; - case 0x0010: - case 0x0011: - case 0x0012: - case 0x0013: - key = Position.PREFIX_IN + (sensorId - 0x0010 + 2); - position.set(key, sensorType > 0); - break; - case 0x001E: - position.set("buttonPresent", sensorType > 0); - break; - case 0x006D: - position.set(Position.KEY_IGNITION, sensorType > 0); - break; - case 0x3000: - position.set(Position.KEY_POWER, record.readUnsignedShortLE() * 0.001); - break; - case 0x3001: - case 0x3002: - case 0x3003: - key = Position.PREFIX_ADC + (0x3003 - sensorId + 3); - position.set(key, record.readUnsignedShortLE() * 0.001); - break; - case 0x3004: - position.set(Position.KEY_BATTERY, record.readUnsignedShortLE() * 0.001); - break; - case 0x300C: - position.set(Position.KEY_RPM, record.readUnsignedShortLE()); - break; - case 0x4003: - position.set(Position.KEY_ODOMETER, record.readUnsignedIntLE() * 5); - break; - case 0x5000: - position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(record.readLongLE())); - break; - case 0xA001: - position.set(Position.KEY_ACCELERATION, record.readFloatLE()); - break; - case 0xA002: - position.set("cornering", record.readFloatLE()); - break; - case 0xA017: - key = Position.PREFIX_TEMP + (sensorId - 0xA017 + 1); - position.set(key, record.readFloatLE()); - break; - default: - key = Position.PREFIX_IO + sensorId; - position.getAttributes().put(key, readValue(record, sensorType)); - break; - } + decodeSensor(position, record, sensorType, sensorId); } } diff --git a/src/main/java/org/traccar/protocol/KhdProtocol.java b/src/main/java/org/traccar/protocol/KhdProtocol.java index f77f4c311..60a2aea7f 100644 --- a/src/main/java/org/traccar/protocol/KhdProtocol.java +++ b/src/main/java/org/traccar/protocol/KhdProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,13 @@ public class KhdProtocol extends BaseProtocol { public KhdProtocol() { setSupportedDataCommands( Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME); + Command.TYPE_ENGINE_RESUME, + Command.TYPE_GET_VERSION, + Command.TYPE_FACTORY_RESET, + Command.TYPE_SET_SPEED_LIMIT, + Command.TYPE_SET_ODOMETER, + Command.TYPE_POSITION_SINGLE); + addServer(new TrackerServer(false, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { diff --git a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java index 16ad616ed..1f3798bd2 100644 --- a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java @@ -125,11 +125,15 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium()); position.set(Position.KEY_STATUS, buf.readUnsignedInt()); - position.set(Position.KEY_HDOP, buf.readUnsignedByte()); - position.set(Position.KEY_VDOP, buf.readUnsignedByte()); - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - buf.skipBytes(5); // other location data + buf.readUnsignedShort(); + buf.readUnsignedByte(); + buf.readUnsignedByte(); + buf.readUnsignedByte(); + buf.readUnsignedByte(); + buf.readUnsignedByte(); + + position.set(Position.KEY_RESULT, buf.readUnsignedByte()); if (type == MSG_PERIPHERAL) { diff --git a/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java b/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java index 4a8df26c8..8aeb9660d 100644 --- a/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2021 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,14 +24,19 @@ import org.traccar.Protocol; public class KhdProtocolEncoder extends BaseProtocolEncoder { + public static final int MSG_ON_DEMAND_TRACK = 0x30; public static final int MSG_CUT_OIL = 0x39; public static final int MSG_RESUME_OIL = 0x38; + public static final int MSG_CHECK_VERSION = 0x3D; + public static final int MSG_FACTORY_RESET = 0xC3; + public static final int MSG_SET_OVERSPEED = 0x3F; + public static final int MSG_DELETE_MILEAGE = 0x66; public KhdProtocolEncoder(Protocol protocol) { super(protocol); } - private ByteBuf encodeCommand(int command, String uniqueId) { + private ByteBuf encodeCommand(int command, String uniqueId, ByteBuf content) { ByteBuf buf = Unpooled.buffer(); @@ -39,7 +44,12 @@ public class KhdProtocolEncoder extends BaseProtocolEncoder { buf.writeByte(0x29); buf.writeByte(command); - buf.writeShort(6); // size + + int length = 6; + if (content != null) { + length += content.readableBytes(); + } + buf.writeShort(length); uniqueId = "00000000".concat(uniqueId); uniqueId = uniqueId.substring(uniqueId.length() - 8); @@ -48,6 +58,10 @@ public class KhdProtocolEncoder extends BaseProtocolEncoder { buf.writeByte(Integer.parseInt(uniqueId.substring(4, 6)) + 0x80); buf.writeByte(Integer.parseInt(uniqueId.substring(6, 8))); + if (content != null) { + buf.writeBytes(content); + } + buf.writeByte(Checksum.xor(buf.nioBuffer())); buf.writeByte(0x0D); // ending @@ -61,9 +75,21 @@ public class KhdProtocolEncoder extends BaseProtocolEncoder { switch (command.getType()) { case Command.TYPE_ENGINE_STOP: - return encodeCommand(MSG_CUT_OIL, uniqueId); + return encodeCommand(MSG_CUT_OIL, uniqueId, null); case Command.TYPE_ENGINE_RESUME: - return encodeCommand(MSG_RESUME_OIL, uniqueId); + return encodeCommand(MSG_RESUME_OIL, uniqueId, null); + case Command.TYPE_GET_VERSION: + return encodeCommand(MSG_CHECK_VERSION, uniqueId, null); + case Command.TYPE_FACTORY_RESET: + return encodeCommand(MSG_FACTORY_RESET, uniqueId, null); + case Command.TYPE_SET_SPEED_LIMIT: + ByteBuf content = Unpooled.buffer(); + content.writeByte(Integer.parseInt(command.getString(Command.KEY_DATA))); + return encodeCommand(MSG_RESUME_OIL, uniqueId, content); + case Command.TYPE_SET_ODOMETER: + return encodeCommand(MSG_DELETE_MILEAGE, uniqueId, null); + case Command.TYPE_POSITION_SINGLE: + return encodeCommand(MSG_ON_DEMAND_TRACK, uniqueId, null); default: return null; } diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java index 89217a39b..68e9e8dd5 100644 --- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java @@ -189,13 +189,17 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder { case 0x28: int beaconFlags = buf.readUnsignedByte(); position.set("tagId", ByteBufUtil.hexDump(buf.readSlice(6))); - buf.readUnsignedByte(); // rssi + position.set("tagRssi", buf.readUnsignedByte()); buf.readUnsignedByte(); // 1m rssi if (BitUtil.check(beaconFlags, 7)) { position.setLatitude(buf.readIntLE() * 0.0000001); position.setLongitude(buf.readIntLE() * 0.0000001); hasLocation = true; } + if (BitUtil.check(beaconFlags, 6)) { + position.set("description", buf.readCharSequence( + endIndex - buf.readerIndex(), StandardCharsets.US_ASCII).toString()); + } break; case 0x30: buf.readUnsignedInt(); // timestamp diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocol.java b/src/main/java/org/traccar/protocol/NavtelecomProtocol.java new file mode 100644 index 000000000..c76b42768 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocol.java @@ -0,0 +1,35 @@ +/* + * Copyright 2021 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; + +public class NavtelecomProtocol extends BaseProtocol { + + public NavtelecomProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 1, 2, 0)); + pipeline.addLast(new Gt02ProtocolDecoder(NavtelecomProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java new file mode 100644 index 000000000..2362b1870 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -0,0 +1,72 @@ +/* + * Copyright 2021 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.Checksum; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; + +public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { + + public NavtelecomProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(4); // preamble + int receiver = buf.readIntLE(); + int sender = buf.readIntLE(); + int length = buf.readUnsignedShortLE(); + buf.readUnsignedByte(); // data checksum + buf.readUnsignedByte(); // header checksum + + String sentence = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString(); + + if (sentence.startsWith("*>S")) { + + String data = "*<S"; + + ByteBuf response = Unpooled.buffer(); + response.writeCharSequence("@NTC", StandardCharsets.US_ASCII); + response.writeIntLE(sender); + response.writeIntLE(receiver); + response.writeShortLE(data.length()); + response.writeByte(Checksum.xor(data)); + response.writeByte(Checksum.xor(response.nioBuffer())); + response.writeCharSequence(data, StandardCharsets.US_ASCII); + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java index 05601ed51..b45fdbb5a 100644 --- a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2021 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. @@ -80,14 +80,14 @@ public class RstProtocolDecoder extends BaseProtocolDecoder { return null; } - String archive = parser.next(); + parser.next(); // archive String model = parser.next(); String firmware = parser.next(); String serial = parser.next(); int index = parser.nextInt(); parser.nextInt(); // type - if (channel != null && archive.equals("A")) { + if (channel != null) { String response = "RST;A;" + model + ";" + firmware + ";" + serial + ";" + index + ";6;FIM;"; channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java index 227a9ac91..b6378f416 100644 --- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2021 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. @@ -110,6 +110,16 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder { case 80: position.set(Position.PREFIX_TEMP + (id - 78), readValue(buf, length, true) * 0.1); break; + case 198: + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + break; + case 199: + case 200: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 201: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; default: position.set(Position.PREFIX_IO + id, readValue(buf, length, false)); break; diff --git a/src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java b/src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java index 6b97f5fe0..bf8bfab77 100644 --- a/src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2021 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,12 +38,12 @@ public class SiwiProtocolDecoder extends BaseProtocolDecoder { .number("(d+),") // device id .number("d+,") // unit no .expression("([A-Z]),") // reason - .number("d+,") // command code + .number("d*,") // command code .number("[^,]*,") // command value .expression("([01]),") // ignition .expression("[01],") // power cut - .expression("[01],") // box open - .number("d+,") // message key + .number("d+,") // flags + .number("[^,]+,") .number("(d+),") // odometer .number("(d+),") // speed .number("(d+),") // satellites @@ -54,6 +54,19 @@ public class SiwiProtocolDecoder extends BaseProtocolDecoder { .number("(d+),") // course .number("(dd)(dd)(dd),") // time (hhmmss) .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("d+,") // signal strength + .number("d+,") // gsm status + .number("d+,") // error code + .number("d+,") // internal status + .number("(d+),") // battery + .number("(d+),") // adc + .number("(d+),") // digital inputs + .number("(d+),") // sensor 1 + .number("(d+),") // sensor 2 + .number("(d+),") // sensor 3 + .number("(d+),") // sensor 4 + .expression("([^,]+),") // hw version + .expression("([^,]+),") // sw version .any() .compile(); @@ -90,6 +103,20 @@ public class SiwiProtocolDecoder extends BaseProtocolDecoder { position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY, "IST")); + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); + position.set(Position.PREFIX_ADC + 1, parser.nextInt() * 0.01); + position.set(Position.KEY_INPUT, parser.nextInt()); + + for (int i = 1; i <= 4; i++) { + int value = parser.nextInt(); + if (value != 0) { + position.set(Position.PREFIX_IO + i, value); + } + } + + position.set(Position.KEY_VERSION_HW, parser.next()); + position.set(Position.KEY_VERSION_FW, parser.next()); + return position; } diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java index 882bed81b..82f0e4061 100644 --- a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2021 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. @@ -193,6 +193,12 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder { case "#TVI#": position.set(Position.KEY_DEVICE_TEMP, Double.parseDouble(data[i])); break; + case "#CFL#": + position.set(Position.KEY_FUEL_LEVEL, Integer.parseInt(data[i])); + break; + case "#CFL2#": + position.set("fuel2", Integer.parseInt(data[i])); + break; case "#IN1#": case "#IN2#": case "#IN3#": diff --git a/src/main/java/org/traccar/protocol/StartekProtocol.java b/src/main/java/org/traccar/protocol/StartekProtocol.java new file mode 100644 index 000000000..d7a4b7d04 --- /dev/null +++ b/src/main/java/org/traccar/protocol/StartekProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2021 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class StartekProtocol extends BaseProtocol { + + public StartekProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Ardi01ProtocolDecoder(StartekProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java new file mode 100644 index 000000000..3868e96fe --- /dev/null +++ b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java @@ -0,0 +1,123 @@ +/* + * Copyright 2021 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class StartekProtocolDecoder extends BaseProtocolDecoder { + + public StartekProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("&&") + .expression(".") // index + .number("d+,") // length + .number("(d+),") // imei + .number("xxx,") // command + .number("(d),") // event + .expression("[^,]*,") // event data + .number("(dd)(dd)(dd)") // date (yyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AV]),") // valid + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .number("(d+),") // satellites + .number("(d+.d+),") // hdop + .number("(d+),") // speed + .number("(d+),") // course + .number("(-?d+),") // altitude + .number("(d+),") // odometer + .number("(d+)|") // mcc + .number("(d+)|") // mnc + .number("(x+)|") // lac + .number("(x+),") // cid + .number("(d+),") // rssi + .number("(x+),") // status + .number("(x+),") // inputs + .number("(x+),") // outputs + .number("(x+)|") // power + .number("(x+)|") // battery + .expression("([^,]+),") // adc + .number("d,") // extended + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_EVENT, parser.nextInt()); + + position.setTime(parser.nextDateTime()); + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_HDOP, parser.nextDouble()); + + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + position.setCourse(parser.nextInt()); + position.setAltitude(parser.nextInt()); + + position.set(Position.KEY_ODOMETER, parser.nextInt()); + + position.setNetwork(new Network(CellTower.from( + parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt(), parser.nextInt()))); + + position.set(Position.KEY_STATUS, parser.nextHexInt()); + position.set(Position.KEY_INPUT, parser.nextHexInt()); + position.set(Position.KEY_OUTPUT, parser.nextHexInt()); + + position.set(Position.KEY_POWER, parser.nextHexInt() * 0.01); + position.set(Position.KEY_BATTERY, parser.nextHexInt() * 0.01); + + String[] adc = parser.next().split("\\|"); + for (int i = 0; i < adc.length; i++) { + position.set(Position.PREFIX_ADC + (i + 1), Integer.parseInt(adc[i], 16) * 0.01); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java index 4042e348c..fe8de3710 100644 --- a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2021 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,6 +24,7 @@ import org.traccar.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.BcdUtil; +import org.traccar.helper.BitUtil; import org.traccar.helper.DateBuilder; import org.traccar.helper.UnitsConverter; import org.traccar.model.CellTower; @@ -151,6 +152,21 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder { Gt06ProtocolDecoder.decodeGps(position, buf, false, TimeZone.getTimeZone("UTC")); + if (buf.readableBytes() >= 5) { + position.setAltitude(buf.readShort()); + + int alarms = buf.readUnsignedByte(); + if (BitUtil.check(alarms, 0)) { + position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); + } + if (BitUtil.check(alarms, 1)) { + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + } + if (BitUtil.check(alarms, 4)) { + position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); + } + } + ByteBuf content = Unpooled.buffer(); content.writeBytes(time); sendResponse(channel, length, type, content); |