From 1268417e9052e36b899bd3f024aa99c01644c3f4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 3 Nov 2015 10:09:05 +1300 Subject: Big improvements to Atrack decoder --- src/org/traccar/model/Event.java | 1 + .../traccar/protocol/AtrackProtocolDecoder.java | 189 ++++++++++++++++----- .../traccar/protocol/UlbotechProtocolDecoder.java | 2 +- .../protocol/AtrackProtocolDecoderTest.java | 29 ++-- 4 files changed, 165 insertions(+), 56 deletions(-) diff --git a/src/org/traccar/model/Event.java b/src/org/traccar/model/Event.java index 172203a86..832e0e7c5 100644 --- a/src/org/traccar/model/Event.java +++ b/src/org/traccar/model/Event.java @@ -50,6 +50,7 @@ public abstract class Event extends Extensible { public static final String KEY_DOOR = "door"; public static final String KEY_RPM = "rpm"; public static final String KEY_HOURS = "hours"; + public static final String KEY_VIN = "vin"; public static final String KEY_OBD_SPEED = "obd-speed"; public static final String KEY_OBD_ODOMETER = "obd-odometer"; diff --git a/src/org/traccar/protocol/AtrackProtocolDecoder.java b/src/org/traccar/protocol/AtrackProtocolDecoder.java index 792f22c07..e939cb88d 100644 --- a/src/org/traccar/protocol/AtrackProtocolDecoder.java +++ b/src/org/traccar/protocol/AtrackProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2014 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2013 - 2015 Anton Tananaev (anton.tananaev@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,17 +24,39 @@ import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.helper.DateBuilder; import org.traccar.helper.UnitsConverter; import org.traccar.model.Event; import org.traccar.model.Position; public class AtrackProtocolDecoder extends BaseProtocolDecoder { + private static final int MIN_DATA_LENGTH = 40; + + private boolean longDate; + private boolean custom; + private String form; + public AtrackProtocolDecoder(AtrackProtocol protocol) { super(protocol); + + longDate = Context.getConfig().getBoolean(getProtocolName() + ".longDate"); + + custom = Context.getConfig().getBoolean(getProtocolName() + ".custom"); + form = Context.getConfig().getString(getProtocolName() + ".form"); + if (form != null) { + custom = true; + } } - private static final int MIN_DATA_LENGTH = 40; + public void setLongDate(boolean longDate) { + this.longDate = longDate; + } + + public void setCustom(boolean custom) { + this.custom = custom; + } private static void sendResponse(Channel channel, SocketAddress remoteAddress, long rawId, int index) { if (channel != null) { @@ -47,32 +69,115 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { } private static String readString(ChannelBuffer buf) { - String result = null; - int length = 0; - while (buf.getByte(buf.readerIndex() + length) != 0) { - length += 1; - } - if (length != 0) { - result = buf.toString(buf.readerIndex(), length, Charset.defaultCharset()); - buf.skipBytes(length); + int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0); + if (index > buf.readerIndex()) { + result = buf.readBytes(index - buf.readerIndex()).toString(Charset.defaultCharset()); } buf.readByte(); - return result; } + private void readCustomData(Position position, ChannelBuffer buf, String form) { + String[] keys = form.substring(1).split("%"); + for (String key : keys) { + switch (key) { + case "SA": + position.set(Event.KEY_SATELLITES, buf.readUnsignedByte()); + break; + case "MV": + position.set(Event.KEY_POWER, buf.readUnsignedShort()); + break; + case "BV": + position.set(Event.KEY_BATTERY, buf.readUnsignedShort()); + break; + case "GQ": + position.set(Event.KEY_GSM, buf.readUnsignedByte()); + break; + case "CE": + position.set(Event.KEY_CELL, buf.readUnsignedInt()); + break; + case "LC": + position.set(Event.KEY_LAC, buf.readUnsignedShort()); + break; + case "CN": + buf.readUnsignedInt(); // mcc + mnc + break; + case "RL": + buf.readUnsignedByte(); // rxlev + break; + case "PC": + buf.readUnsignedInt(); // pulse count + break; + case "AT": + position.setAltitude(buf.readUnsignedInt()); + break; + case "RP": + position.set(Event.KEY_RPM, buf.readUnsignedShort()); + break; + case "GS": + buf.readUnsignedByte(); // gsm status + break; + case "DT": + position.set(Event.KEY_ARCHIVE, buf.readUnsignedByte() == 1); + break; + case "VN": + position.set(Event.KEY_VIN, readString(buf)); + break; + case "MF": + buf.readUnsignedShort(); // mass air flow rate + break; + case "EL": + buf.readUnsignedByte(); // engine load + break; + case "TR": + buf.readUnsignedByte(); // throttle position + break; + case "ET": + buf.readUnsignedShort(); // engine coolant temp + break; + case "FL": + position.set(Event.KEY_FUEL, buf.readUnsignedByte()); + break; + case "ML": + buf.readUnsignedByte(); // mil status + break; + case "FC": + buf.readUnsignedInt(); // fuel used + break; + case "CI": + readString(buf); // format string + break; + case "AV1": + position.set(Event.PREFIX_ADC + 1, buf.readUnsignedShort()); + break; + case "NC": + readString(buf); // gsm neighbor cell info + break; + case "SM": + buf.readUnsignedShort(); // max speed between reports + break; + case "GL": + readString(buf); // google link + break; + case "MA": + readString(buf); // mac address + break; + default: + break; + } + } + } + @Override protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) - throws Exception { + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { ChannelBuffer buf = (ChannelBuffer) msg; - // Keep alive message if (buf.getUnsignedShort(buf.readerIndex()) == 0xfe02) { if (channel != null) { - channel.write(buf, remoteAddress); + channel.write(buf, remoteAddress); // keep-alive message } return null; } @@ -82,72 +187,70 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedShort(); // length int index = buf.readUnsignedShort(); - // Get device id long id = buf.readLong(); if (!identify(String.valueOf(id), channel, remoteAddress)) { return null; } - // Send acknowledgement sendResponse(channel, remoteAddress, id, index); List positions = new LinkedList<>(); while (buf.readableBytes() >= MIN_DATA_LENGTH) { - // Create new position Position position = new Position(); - position.setDeviceId(getDeviceId()); position.setProtocol(getProtocolName()); + position.setDeviceId(getDeviceId()); + + if (longDate) { + + DateBuilder dateBuilder = new DateBuilder() + .setDate(buf.readUnsignedShort(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); - // Date and time - position.setTime(new Date(buf.readUnsignedInt() * 1000)); // gps time - buf.readUnsignedInt(); // rtc time - buf.readUnsignedInt(); // send time + buf.skipBytes(7 + 7); + + + } else { + + position.setFixTime(new Date(buf.readUnsignedInt() * 1000)); + position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000)); + buf.readUnsignedInt(); // send time + } - // Coordinates position.setValid(true); position.setLongitude(buf.readInt() * 0.000001); position.setLatitude(buf.readInt() * 0.000001); - - // Course position.setCourse(buf.readUnsignedShort()); - // Report type position.set(Event.KEY_TYPE, buf.readUnsignedByte()); - - // Odometer position.set(Event.KEY_ODOMETER, buf.readUnsignedInt() * 0.1); - - // Accuracy position.set(Event.KEY_HDOP, buf.readUnsignedShort() * 0.1); - - // Input position.set(Event.KEY_INPUT, buf.readUnsignedByte()); - // Speed position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - // Output position.set(Event.KEY_OUTPUT, buf.readUnsignedByte()); - - // ADC position.set(Event.PREFIX_ADC + 1, buf.readUnsignedShort() * 0.001); - // Driver position.set("driver", readString(buf)); - // Temperature position.set(Event.PREFIX_TEMP + 1, buf.readShort() * 0.1); position.set(Event.PREFIX_TEMP + 2, buf.readShort() * 0.1); - // Text Message position.set("message", readString(buf)); - // With AT$FORM Command you can extend atrack protocol. - // For example adding AT$FORM %FC /Fuel used you can add the line in this position: - // position.set("fuelused", buf.readUnsignedInt() * 0.1); + if (custom) { + String form = this.form; + if (form == null) { + form = readString(buf).substring("%CI".length()); + } + readCustomData(position, buf, form); + } + positions.add(position); + } return positions; diff --git a/src/org/traccar/protocol/UlbotechProtocolDecoder.java b/src/org/traccar/protocol/UlbotechProtocolDecoder.java index b015e768a..a3edfdb07 100644 --- a/src/org/traccar/protocol/UlbotechProtocolDecoder.java +++ b/src/org/traccar/protocol/UlbotechProtocolDecoder.java @@ -197,7 +197,7 @@ public class UlbotechProtocolDecoder extends BaseProtocolDecoder { break; case DATA_VIN: - position.set("vin", buf.readBytes(length).toString(Charset.defaultCharset())); + position.set(Event.KEY_VIN, buf.readBytes(length).toString(Charset.defaultCharset())); break; case DATA_RFID: diff --git a/test/org/traccar/protocol/AtrackProtocolDecoderTest.java b/test/org/traccar/protocol/AtrackProtocolDecoderTest.java index 882501e9e..72c54f1e6 100644 --- a/test/org/traccar/protocol/AtrackProtocolDecoderTest.java +++ b/test/org/traccar/protocol/AtrackProtocolDecoderTest.java @@ -1,9 +1,7 @@ package org.traccar.protocol; -import org.jboss.netty.buffer.ChannelBuffers; import org.junit.Test; import org.traccar.ProtocolDecoderTest; -import org.traccar.helper.ChannelBufferTools; public class AtrackProtocolDecoderTest extends ProtocolDecoderTest { @@ -12,12 +10,26 @@ public class AtrackProtocolDecoderTest extends ProtocolDecoderTest { AtrackProtocolDecoder decoder = new AtrackProtocolDecoder(new AtrackProtocol()); + decoder.setLongDate(true); + + verifyPositions(decoder, binary( + "0203b494003c00eb00014104d8dd3a3e07de011b0b1f0307de011b0b1f0307de011b0b1f0300307f28030574d30000020000000600160100020000000007d007d000")); + + decoder.setLongDate(false); + + decoder.setCustom(true); + + verifyPositions(decoder, binary( + "405025e30096eb730001452efaf6a7d6562fe4f8562fe4f7562fe52c02a006d902273f810064650000e0f5000a0100000000000007d007d000254349255341254d5625425625475125415400090083002a1a000001a8562fe4f8562fe4f7562fe52c02a006d902273f810064020000e0f5000a0100000000000007d007d000254349255341254d5625425625475125415400090083002a1a000001a8")); + + decoder.setCustom(false); + verifyNothing(decoder, binary( "fe0200014104d8f196820001")); - // invalid GPS data - //verifyPositions(decoder, binary( - // "40503835003300070001441c3d8ed1c400000000000000c9000000c900000000000000000000020000000003de0100000000000007d007d000")); + verifyPositions(decoder, binary( + "40503835003300070001441c3d8ed1c400000000000000c9000000c900000000000000000000020000000003de0100000000000007d007d000"), + position("1970-01-01 00:00:00.000", true, 0.00000, 0.00000)); verifyPositions(decoder, binary( "4050993f005c000200014104d8f19682525666c252568c3c52568c63ffc8338402698885000002000009cf03de0100000000000007d007d000525666c252568c5a52568c63ffc8338402698885000002000009cf03de0100000000000007d007d000")); @@ -28,13 +40,6 @@ public class AtrackProtocolDecoderTest extends ProtocolDecoderTest { verifyPositions(decoder, binary( "40501e58003301e000014104d8f19682525ecd5d525ee344525ee35effc88815026ab4d70000020000104403de01000b0000000007d007d000000000000000")); - // 7-byte date - //verifyPosition(decoder, binary( - // "0203b494003c00eb00014104d8dd3a3e07de011b0b1f0307de011b0b1f0307de011b0b1f0300307f28030574d30000020000000600160100020000000007d007d000")); - - //verifyPosition(decoder, binary( - // "4050d2c500da055200014104d8f19682530755515307555053075581ffbba66a0231295c001902000000da000a0100830000000007d007d000000000001200080e090085530755605307555f53075582ffbbb04102313b4b001802000000e0000c0100850000000007d007d000000000001200080d0000865307556f5307556e53075582ffbbbbea02314b49002402000000e5000a01007b0000000007d007d000000000001200080d0200855307557e5307557d53075582ffbbc98702315982002502000000ea000901007a0000000007d007d000000000001300180d08007b")); - } } -- cgit v1.2.3