aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java')
-rw-r--r--src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java212
1 files changed, 212 insertions, 0 deletions
diff --git a/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java
new file mode 100644
index 000000000..0afec67ad
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 Luis Parada (luis.parada@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import 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.DateBuilder;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.regex.Pattern;
+
+public class Pt502ProtocolDecoder extends BaseProtocolDecoder {
+
+ private static final int MAX_CHUNK_SIZE = 960;
+
+ private ByteBuf photo;
+
+ public Pt502ProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .any().text("$")
+ .expression("([^,]+),") // type
+ .number("(d+),") // id
+ .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss)
+ .expression("([AV]),") // validity
+ .number("(d+)(dd.dddd),") // latitude
+ .expression("([NS]),")
+ .number("(d+)(dd.dddd),") // longitude
+ .expression("([EW]),")
+ .number("(d+.d+)?,") // speed
+ .number("(d+.d+)?,") // course
+ .number("(dd)(dd)(dd),,,") // date (ddmmyy)
+ .expression("./")
+ .expression("([01])+,") // input
+ .expression("([01])+/") // output
+ .expression("([^/]+)?/") // adc
+ .number("(d+)") // odometer
+ .expression("/([^/]+)?/") // rfid
+ .number("(xxx)").optional(2) // state
+ .any()
+ .compile();
+
+ private String decodeAlarm(String value) {
+ switch (value) {
+ case "IN1":
+ return Position.ALARM_SOS;
+ case "GOF":
+ return Position.ALARM_GEOFENCE;
+ case "TOW":
+ return Position.ALARM_TOW;
+ case "HDA":
+ return Position.ALARM_ACCELERATION;
+ case "HDB":
+ return Position.ALARM_BRAKING;
+ case "FDA":
+ return Position.ALARM_FATIGUE_DRIVING;
+ case "SKA":
+ return Position.ALARM_VIBRATION;
+ case "PMA":
+ return Position.ALARM_MOVEMENT;
+ case "CPA":
+ return Position.ALARM_POWER_CUT;
+ default:
+ return null;
+ }
+ }
+
+ private Position decodePosition(Channel channel, SocketAddress remoteAddress, String sentence) {
+
+ Parser parser = new Parser(PATTERN, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.set(Position.KEY_ALARM, decodeAlarm(parser.next()));
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
+
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setSpeed(parser.nextDouble(0));
+ position.setCourse(parser.nextDouble(0));
+
+ dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
+ position.setTime(dateBuilder.getDate());
+
+ position.set(Position.KEY_INPUT, parser.next());
+ position.set(Position.KEY_OUTPUT, parser.next());
+
+ if (parser.hasNext()) {
+ String[] values = parser.next().split(",");
+ for (int i = 0; i < values.length; i++) {
+ position.set(Position.PREFIX_ADC + (i + 1), Integer.parseInt(values[i], 16));
+ }
+ }
+
+ position.set(Position.KEY_ODOMETER, parser.nextInt(0));
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next());
+
+ if (parser.hasNext()) {
+ int value = parser.nextHexInt(0);
+ position.set(Position.KEY_BATTERY, value >> 8);
+ position.set(Position.KEY_RSSI, (value >> 4) & 0xf);
+ position.set(Position.KEY_SATELLITES, value & 0xf);
+ }
+
+ return position;
+ }
+
+ private void requestPhotoFragment(Channel channel) {
+ if (channel != null) {
+ int offset = photo.writerIndex();
+ int size = Math.min(photo.writableBytes(), MAX_CHUNK_SIZE);
+ channel.writeAndFlush(new NetworkMessage("#PHD" + offset + "," + size + "\r\n", channel.remoteAddress()));
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ByteBuf buf = (ByteBuf) msg;
+
+ int typeEndIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ',');
+ String type = buf.toString(buf.readerIndex(), typeEndIndex - buf.readerIndex(), StandardCharsets.US_ASCII);
+
+ if (type.startsWith("$PHD")) {
+
+ int dataIndex = buf.indexOf(typeEndIndex + 1, buf.writerIndex(), (byte) ',') + 1;
+ buf.readerIndex(dataIndex);
+
+ if (photo != null) {
+
+ photo.writeBytes(buf.readSlice(buf.readableBytes()));
+
+ if (photo.writableBytes() > 0) {
+
+ requestPhotoFragment(channel);
+
+ } else {
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
+ String uniqueId = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getUniqueId();
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, null);
+
+ position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg"));
+ photo.release();
+ photo = null;
+
+ return position;
+
+ }
+
+ }
+
+ } else {
+
+ if (type.startsWith("$PHO")) {
+ int size = Integer.parseInt(type.split("-")[0].substring(4));
+ if (size > 0) {
+ photo = Unpooled.buffer(size);
+ requestPhotoFragment(channel);
+ }
+ }
+
+ return decodePosition(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII));
+
+ }
+
+ return null;
+ }
+
+}