diff options
Diffstat (limited to 'src/main/java/org/traccar')
14 files changed, 644 insertions, 34 deletions
diff --git a/src/main/java/org/traccar/BasePipelineFactory.java b/src/main/java/org/traccar/BasePipelineFactory.java index a92dba7fa..5a5850a86 100644 --- a/src/main/java/org/traccar/BasePipelineFactory.java +++ b/src/main/java/org/traccar/BasePipelineFactory.java @@ -134,8 +134,8 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> { FilterHandler.class, GeocoderHandler.class, MotionHandler.class, - EngineHoursHandler.class, CopyAttributesHandler.class, + EngineHoursHandler.class, ComputedAttributesHandler.class, WebDataHandler.class, DefaultDataHandler.class); diff --git a/src/main/java/org/traccar/notification/NotificatorManager.java b/src/main/java/org/traccar/notification/NotificatorManager.java index a4080a38d..191748379 100644 --- a/src/main/java/org/traccar/notification/NotificatorManager.java +++ b/src/main/java/org/traccar/notification/NotificatorManager.java @@ -31,6 +31,7 @@ import org.traccar.notificators.NotificatorNull; import org.traccar.notificators.Notificator; import org.traccar.notificators.NotificatorSms; import org.traccar.notificators.NotificatorWeb; +import org.traccar.notificators.NotificatorTelegram; public final class NotificatorManager { @@ -57,6 +58,9 @@ public final class NotificatorManager { case "firebase": defaultNotificator = NotificatorFirebase.class.getCanonicalName(); break; + case "telegram": + defaultNotificator = NotificatorTelegram.class.getCanonicalName(); + break; default: break; } diff --git a/src/main/java/org/traccar/notificators/NotificatorTelegram.java b/src/main/java/org/traccar/notificators/NotificatorTelegram.java new file mode 100644 index 000000000..89c15ba7c --- /dev/null +++ b/src/main/java/org/traccar/notificators/NotificatorTelegram.java @@ -0,0 +1,77 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.notificators; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.Event; +import org.traccar.model.Position; +import org.traccar.notification.NotificationFormatter; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.InvocationCallback; + +public class NotificatorTelegram extends Notificator { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorTelegram.class); + + private String url; + private String chatId; + + public static class Message { + @JsonProperty("chat_id") + private String chatId; + @JsonProperty("text") + private String text; + @JsonProperty("parse_mode") + private String parseMode = "html"; + } + + public NotificatorTelegram() { + url = String.format( + "https://api.telegram.org/bot%s/sendMessage", + Context.getConfig().getString("notificator.telegram.key")); + chatId = Context.getConfig().getString("notificator.Telegram.chatid"); + } + + @Override + public void sendSync(long userId, Event event, Position position) { + + Message message = new Message(); + message.chatId = chatId; + message.text = NotificationFormatter.formatShortMessage(userId, event, position); + + Context.getClient().target(url).request() + .async().post(Entity.json(message), new InvocationCallback<Object>() { + @Override + public void completed(Object o) { + } + + @Override + public void failed(Throwable throwable) { + LOGGER.warn("Telegram API error", throwable); + } + }); + } + + @Override + public void sendAsync(long userId, Event event, Position position) { + sendSync(userId, event, position); + } + +} diff --git a/src/main/java/org/traccar/protocol/FifotrackFrameDecoder.java b/src/main/java/org/traccar/protocol/FifotrackFrameDecoder.java new file mode 100644 index 000000000..967b17a64 --- /dev/null +++ b/src/main/java/org/traccar/protocol/FifotrackFrameDecoder.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +import java.nio.charset.StandardCharsets; + +public class FifotrackFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 10) { + return null; + } + + int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); + if (index != -1) { + int length = index - buf.readerIndex() + 3 + Integer.parseInt( + buf.toString(buf.readerIndex() + 2, index - buf.readerIndex() - 2, StandardCharsets.US_ASCII)); + if (buf.readableBytes() >= length + 2) { + ByteBuf frame = buf.readRetainedSlice(length); + buf.skipBytes(2); // delimiter + return frame; + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocol.java b/src/main/java/org/traccar/protocol/FifotrackProtocol.java index 371e01e55..12cd00b4e 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocol.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,8 +15,6 @@ */ package org.traccar.protocol; -import io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; @@ -28,9 +26,8 @@ public class FifotrackProtocol extends BaseProtocol { addServer(new TrackerServer(false, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new FifotrackFrameDecoder()); pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); pipeline.addLast(new FifotrackProtocolDecoder(FifotrackProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java index 35696ee12..a9cf025af 100644 --- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -19,11 +19,11 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; import org.traccar.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.Checksum; -import org.traccar.helper.DataConverter; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; import org.traccar.helper.UnitsConverter; @@ -32,6 +32,7 @@ import org.traccar.model.Network; import org.traccar.model.Position; import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; import java.util.regex.Pattern; public class FifotrackProtocolDecoder extends BaseProtocolDecoder { @@ -87,12 +88,11 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { .text("$$") .number("d+,") // length .number("(d+),") // imei - .expression("([^*]+),") // photo id + .number("x+,") // index + .expression("[^,]+,") // type + .expression("([^,]+),") // photo id .number("(d+),") // offset .number("(d+),") // size - .number("(x+)") // data - .text("*") - .number("xx") .compile(); private void requestPhoto(Channel channel, SocketAddress socketAddress, String imei, String file) { @@ -165,11 +165,14 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - String sentence = (String) msg; - int typeIndex = sentence.indexOf(',', sentence.indexOf(',', sentence.indexOf(',') + 1) + 1) + 1; - String type = sentence.substring(typeIndex, typeIndex + 3); + ByteBuf buf = (ByteBuf) msg; + int typeIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ',') + 1; + typeIndex = buf.indexOf(typeIndex, buf.writerIndex(), (byte) ',') + 1; + typeIndex = buf.indexOf(typeIndex, buf.writerIndex(), (byte) ',') + 1; + String type = buf.toString(typeIndex, 3, StandardCharsets.US_ASCII); if (type.equals("D05")) { + String sentence = buf.toString(StandardCharsets.US_ASCII); Parser parser = new Parser(PATTERN_PHOTO, sentence); if (parser.matches()) { String imei = parser.next(); @@ -179,16 +182,35 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder { requestPhoto(channel, remoteAddress, imei, photoId); } } else if (type.equals("D06")) { + if (photo == null) { + return null; + } + int dataIndex = buf.indexOf(typeIndex + 4, buf.writerIndex(), (byte) ',') + 1; + dataIndex = buf.indexOf(dataIndex, buf.writerIndex(), (byte) ',') + 1; + dataIndex = buf.indexOf(dataIndex, buf.writerIndex(), (byte) ',') + 1; + String sentence = buf.toString(buf.readerIndex(), dataIndex, StandardCharsets.US_ASCII); Parser parser = new Parser(PATTERN_PHOTO_DATA, sentence); if (parser.matches()) { String imei = parser.next(); String photoId = parser.next(); parser.nextInt(); // offset parser.nextInt(); // size - photo.writeBytes(DataConverter.parseHex(parser.next())); - requestPhoto(channel, remoteAddress, imei, photoId); + buf.readerIndex(dataIndex); + photo.writeBytes(buf.readBytes(buf.readableBytes() - 3)); // ignore checksum + if (photo.isWritable()) { + requestPhoto(channel, remoteAddress, imei, photoId); + } else { + Position position = new Position(getProtocolName()); + position.setDeviceId(getDeviceSession(channel, remoteAddress, imei).getDeviceId()); + getLastLocation(position, null); + position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(imei, photo, "jpg")); + photo.release(); + photo = null; + return position; + } } } else { + String sentence = buf.toString(StandardCharsets.US_ASCII); return decodeLocation(channel, remoteAddress, sentence); } diff --git a/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java index c4443a00b..22bbe4441 100644 --- a/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java @@ -88,19 +88,18 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder { } private Integer decodeBattery(int value) { - switch (value) { - case 6: - return 100; - case 5: - return 80; - case 4: - return 60; - case 3: - return 20; - case 2: - return 10; - default: - return null; + if (value == 0) { + return null; + } else if (value <= 3) { + return (value - 1) * 10; + } else if (value <= 6) { + return (value - 1) * 20; + } else if (value <= 100) { + return value; + } else if (value >= 0xF1 && value <= 0xF6) { + return value - 0xF0; + } else { + return null; } } diff --git a/src/main/java/org/traccar/protocol/PebbellProtocol.java b/src/main/java/org/traccar/protocol/PebbellProtocol.java new file mode 100644 index 000000000..762c30585 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PebbellProtocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import java.nio.ByteOrder; + +public class PebbellProtocol extends BaseProtocol { + + public PebbellProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, 4, 0, true)); + pipeline.addLast(new PebbellProtocolDecoder(PebbellProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/PebbellProtocolDecoder.java b/src/main/java/org/traccar/protocol/PebbellProtocolDecoder.java new file mode 100644 index 000000000..7271c60d8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PebbellProtocolDecoder.java @@ -0,0 +1,153 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; + +public class PebbellProtocolDecoder extends BaseProtocolDecoder { + + public PebbellProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_DATA = 0x01; + + private String decodeAlarm(int code) { + if (BitUtil.check(code, 0)) { + return Position.ALARM_LOW_BATTERY; + } + if (BitUtil.check(code, 1)) { + return Position.ALARM_OVERSPEED; + } + if (BitUtil.check(code, 2)) { + return Position.ALARM_FALL_DOWN; + } + if (BitUtil.check(code, 8)) { + return Position.ALARM_POWER_OFF; + } + if (BitUtil.check(code, 9)) { + return Position.ALARM_POWER_ON; + } + if (BitUtil.check(code, 12)) { + return Position.ALARM_SOS; + } + return null; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // header + buf.readUnsignedByte(); // properties + buf.readUnsignedShortLE(); // length + buf.readUnsignedShortLE(); // checksum + buf.readUnsignedShortLE(); // index + int type = buf.readUnsignedByte(); + + if (type == MSG_DATA) { + + Position position = new Position(getProtocolName()); + + while (buf.isReadable()) { + int endIndex = buf.readUnsignedByte() + buf.readerIndex(); + int key = buf.readUnsignedByte(); + switch (key) { + case 0x01: + DeviceSession deviceSession = getDeviceSession( + channel, remoteAddress, buf.readBytes(15).toString(StandardCharsets.US_ASCII)); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + break; + case 0x02: + position.set(Position.KEY_ALARM, decodeAlarm(buf.readIntLE())); + break; + case 0x20: + position.setLatitude(buf.readIntLE() * 0.0000001); + position.setLongitude(buf.readIntLE() * 0.0000001); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); + position.setCourse(buf.readUnsignedShortLE()); + position.setAltitude(buf.readShortLE()); + position.setValid(buf.readUnsignedShortLE() > 0); + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + break; + case 0x21: + int mcc = buf.readUnsignedShortLE(); + int mnc = buf.readUnsignedByte(); + if (position.getNetwork() == null) { + position.setNetwork(new Network()); + } + while (buf.readerIndex() < endIndex) { + int rssi = buf.readByte(); + position.getNetwork().addCellTower(CellTower.from( + mcc, mnc, buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), rssi)); + } + break; + case 0x22: + if (position.getNetwork() == null) { + position.setNetwork(new Network()); + } + while (buf.readerIndex() < endIndex) { + int rssi = buf.readByte(); + String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); + position.getNetwork().addWifiAccessPoint(WifiAccessPoint.from( + mac.substring(0, mac.length() - 1), rssi)); + } + break; + case 0x40: + buf.readUnsignedIntLE(); // timestamp + int heartRate = buf.readUnsignedByte(); + if (heartRate > 1) { + position.set(Position.KEY_HEART_RATE, heartRate); + } + break; + default: + break; + } + buf.readerIndex(endIndex); + } + + if (!position.getAttributes().containsKey(Position.KEY_SATELLITES)) { + getLastLocation(position, null); + } + + return position.getDeviceId() > 0 ? position : null; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/RadarProtocol.java b/src/main/java/org/traccar/protocol/RadarProtocol.java new file mode 100644 index 000000000..9783778f0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RadarProtocol.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class RadarProtocol extends BaseProtocol { + + public RadarProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 12, 2, -14, 0)); + pipeline.addLast(new RadarProtocolDecoder(RadarProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/RadarProtocolDecoder.java b/src/main/java/org/traccar/protocol/RadarProtocolDecoder.java new file mode 100644 index 000000000..765171e9c --- /dev/null +++ b/src/main/java/org/traccar/protocol/RadarProtocolDecoder.java @@ -0,0 +1,191 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.BitSet; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class RadarProtocolDecoder extends BaseProtocolDecoder { + + public RadarProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_TRACKING = 0x4C; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // product id + buf.readUnsignedByte(); // product version + + String serialNumber = String.valueOf(buf.readUnsignedInt()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, serialNumber); + if (deviceSession == null) { + return null; + } + + buf.readUnsignedByte(); // index + buf.readUnsignedInt(); // timestamp + int type = buf.readUnsignedByte(); + buf.readUnsignedShort(); // length + + if (type == MSG_TRACKING) { + + buf.readUnsignedShort(); // memory count + buf.readUnsignedShort(); // memory index + int count = buf.readUnsignedShort(); + buf.readUnsignedShort(); // first index + + List<Position> positions = new LinkedList<>(); + + for (int index = 0; index < count; index++) { + + Position position = new Position(getProtocolName()); + + position.set(Position.KEY_EVENT, buf.readUnsignedShort()); + + int maskLength = buf.readUnsignedByte(); + BitSet mask = BitSet.valueOf(buf.nioBuffer(buf.readerIndex(), maskLength)); + buf.skipBytes(maskLength); + + buf.readUnsignedShort(); // length + + if (mask.get(0)) { + position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000)); + } + if (mask.get(1)) { + position.setFixTime(new Date(buf.readUnsignedInt() * 1000)); + } + if (mask.get(2)) { + position.setLatitude(buf.readInt() / 360000.0); + } + if (mask.get(3)) { + position.setLongitude(buf.readInt() / 360000.0); + } + if (mask.get(4)) { + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + } + if (mask.get(5)) { + position.setCourse(buf.readUnsignedShort() * 0.1); + } + if (mask.get(6)) { + position.setAltitude(buf.readShort()); + } + if (mask.get(7)) { + int flags = buf.readUnsignedByte(); + position.setValid(BitUtil.check(flags, 0)); + position.set(Position.KEY_SATELLITES, BitUtil.from(flags, 4)); + } + if (mask.get(8)) { + long flags = buf.readUnsignedInt(); + position.set(Position.KEY_IGNITION, BitUtil.check(flags, 0)); + position.set(Position.KEY_CHARGE, BitUtil.check(flags, 1)); + position.set(Position.KEY_MOTION, BitUtil.check(flags, 2)); + for (int i = 0; i < 3; i++) { + position.set(Position.PREFIX_IN + i, BitUtil.check(flags, 4 + i)); + } + } + if (mask.get(9)) { + int flags = buf.readUnsignedShort(); + position.set(Position.KEY_BLOCKED, BitUtil.check(flags, 0)); + position.set(Position.PREFIX_IN + 0, BitUtil.check(flags, 4)); + } + for (int i = 10; i <= 14; i++) { + if (mask.get(i)) { + buf.readUnsignedShort(); // reserved + } + } + if (mask.get(15)) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100); + } + if (mask.get(16)) { + buf.readUnsignedInt(); // reserved + } + for (int i = 17; i <= 27; i++) { + if (mask.get(i)) { + buf.readUnsignedByte(); // reserved + } + } + for (int i = 28; i <= 37; i += 2) { + if (mask.get(i)) { + buf.skipBytes(12); // reserved + } + if (mask.get(i + 1)) { + buf.readUnsignedByte(); // reserved + } + } + if (mask.get(38)) { + buf.skipBytes(6); // driver id + } + if (mask.get(39)) { + buf.readUnsignedShort(); // hardware problems + } + if (mask.get(40)) { + buf.readShort(); // acceleration x + } + if (mask.get(41)) { + buf.readShort(); // acceleration y + } + if (mask.get(42)) { + buf.readShort(); // acceleration z + } + if (mask.get(43)) { + buf.skipBytes(10); // operator + } + if (mask.get(44)) { + buf.readUnsignedShort(); // power + } + for (int i = 45; i <= 49; i++) { + if (mask.get(i)) { + buf.readUnsignedByte(); // reserved + } + } + if (mask.get(50)) { + buf.readShort(); // tilt + } + + if (position.getDeviceTime() != null && position.getFixTime() != null) { + positions.add(position); + } + + } + + // ACK 0x9C + + return positions.isEmpty() ? null : positions; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/SuntechFrameDecoder.java b/src/main/java/org/traccar/protocol/SuntechFrameDecoder.java new file mode 100644 index 000000000..de8de17f0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SuntechFrameDecoder.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class SuntechFrameDecoder extends BaseFrameDecoder { + + private ByteBuf readFrame(ByteBuf buf, int delimiterIndex) { + ByteBuf frame = buf.readRetainedSlice(delimiterIndex - buf.readerIndex()); + buf.skipBytes(1); // delimiter + return frame; + } + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + int delimiterIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\r'); + while (delimiterIndex > 0) { + if (delimiterIndex + 1 < buf.writerIndex() && buf.getByte(delimiterIndex + 1) == '\n') { + delimiterIndex = buf.indexOf(delimiterIndex + 1, buf.writerIndex(), (byte) '\r'); + } else { + return readFrame(buf, delimiterIndex); + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/SuntechProtocol.java b/src/main/java/org/traccar/protocol/SuntechProtocol.java index 29ae114e7..48d6e81c1 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocol.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ package org.traccar.protocol; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.model.Command; @@ -37,7 +36,7 @@ public class SuntechProtocol extends BaseProtocol { addServer(new TrackerServer(false, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r')); + pipeline.addLast(new SuntechFrameDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); pipeline.addLast(new SuntechProtocolEncoder()); diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java index f67ff88db..2a06d35e5 100644 --- a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_HEADER = new PatternBuilder() .number("#(d+)#") // imei .any() - .expression("([^#]+)#") // status + .expression("#([^#]+)#") // status .number("d+") // number of records .compile(); |