aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/org/traccar/protocol/UproProtocol.java4
-rw-r--r--src/org/traccar/protocol/UproProtocolDecoder.java104
-rw-r--r--test/org/traccar/protocol/UproProtocolDecoderTest.java41
3 files changed, 92 insertions, 57 deletions
diff --git a/src/org/traccar/protocol/UproProtocol.java b/src/org/traccar/protocol/UproProtocol.java
index ae6cac603..c00f859ee 100644
--- a/src/org/traccar/protocol/UproProtocol.java
+++ b/src/org/traccar/protocol/UproProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2016 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,7 +17,6 @@ package org.traccar.protocol;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
@@ -37,7 +36,6 @@ public class UproProtocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(1024, '#'));
- pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("stringEncoder", new StringEncoder());
pipeline.addLast("objectDecoder", new UproProtocolDecoder(UproProtocol.this));
}
diff --git a/src/org/traccar/protocol/UproProtocolDecoder.java b/src/org/traccar/protocol/UproProtocolDecoder.java
index 24a0f5dcd..e47dd8595 100644
--- a/src/org/traccar/protocol/UproProtocolDecoder.java
+++ b/src/org/traccar/protocol/UproProtocolDecoder.java
@@ -15,6 +15,8 @@
*/
package org.traccar.protocol;
+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.DeviceSession;
@@ -25,6 +27,8 @@ import org.traccar.helper.PatternBuilder;
import org.traccar.model.Position;
import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.text.ParseException;
import java.util.regex.Pattern;
public class UproProtocolDecoder extends BaseProtocolDecoder {
@@ -33,19 +37,17 @@ public class UproProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- private static final Pattern PATTERN = new PatternBuilder()
+ private static final Pattern PATTERN_HEADER = new PatternBuilder()
.text("*")
.expression("..20")
.expression("([01])") // ack
.number("(d+),") // device id
.expression("(.)") // type
.expression("(.)") // subtype
- .expression("(.*)") // content
- .expression("#?") // delimiter
+ .any()
.compile();
private static final Pattern PATTERN_LOCATION = new PatternBuilder()
- .text("A")
.number("(dd)(dd)(dd)") // time
.number("(dd)(dd)(dddd)") // latitude
.number("(ddd)(dd)(dddd)") // longitude
@@ -88,7 +90,19 @@ public class UproProtocolDecoder extends BaseProtocolDecoder {
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- Parser parser = new Parser(PATTERN, (String) msg);
+ ChannelBuffer buf = (ChannelBuffer) msg;
+
+ if (buf.getByte(buf.readerIndex()) != '*') {
+ throw new ParseException(null, 0);
+ }
+
+ int headerIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '&');
+ if (headerIndex < 0) {
+ headerIndex = buf.writerIndex();
+ }
+ String header = buf.readBytes(headerIndex - buf.readerIndex()).toString(StandardCharsets.US_ASCII);
+
+ Parser parser = new Parser(PATTERN_HEADER, header);
if (!parser.matches()) {
return null;
}
@@ -111,37 +125,57 @@ public class UproProtocolDecoder extends BaseProtocolDecoder {
channel.write("*MG20Y" + type + subtype + "#");
}
- String[] data = parser.next().split("&");
- for (int i = 0; i < data.length; i++) {
- if (i != 0) {
- switch (data[i].charAt(0)) {
- case 'A':
- decodeLocation(position, data[i]);
- break;
- case 'B':
- position.set(Position.KEY_STATUS, data[i].substring(1));
- break;
- case 'C':
- long odometer = 0;
- for (int j = 1; j < data[i].length(); j++) {
- odometer <<= 4;
- odometer += data[i].charAt(j) - '0';
- }
- position.set(Position.KEY_ODOMETER, odometer * 2 * 1852 / 3600);
- break;
- case 'P':
- position.set(Position.KEY_MCC, Integer.parseInt(data[i].substring(1, 5)));
- position.set(Position.KEY_MNC, Integer.parseInt(data[i].substring(5, 9)));
- position.set(Position.KEY_LAC, Integer.parseInt(data[i].substring(9, 13), 16));
- position.set(Position.KEY_CID, Integer.parseInt(data[i].substring(13, 17), 16));
- break;
- case 'S':
- position.set("obd", data[i]);
- break;
- default:
- break;
- }
+ while (buf.readable()) {
+
+ buf.readByte(); // skip delimiter
+
+ byte dataType = buf.readByte();
+
+ int delimiterIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '&');
+ if (delimiterIndex < 0) {
+ delimiterIndex = buf.writerIndex();
}
+
+ ChannelBuffer data = buf.readBytes(delimiterIndex - buf.readerIndex());
+
+ switch (dataType) {
+ case 'A':
+ decodeLocation(position, data.toString(StandardCharsets.US_ASCII));
+ break;
+ case 'B':
+ position.set(Position.KEY_STATUS, data.toString(StandardCharsets.US_ASCII));
+ break;
+ case 'C':
+ long odometer = 0;
+ while (data.readable()) {
+ odometer <<= 4;
+ odometer += data.readByte() - (byte) '0';
+ }
+ position.set(Position.KEY_ODOMETER, odometer * 2 * 1852 / 3600);
+ break;
+ case 'P':
+ position.set(Position.KEY_MCC,
+ Integer.parseInt(data.readBytes(4).toString(StandardCharsets.US_ASCII)));
+ position.set(Position.KEY_MNC,
+ Integer.parseInt(data.readBytes(4).toString(StandardCharsets.US_ASCII)));
+ position.set(Position.KEY_LAC,
+ Integer.parseInt(data.readBytes(4).toString(StandardCharsets.US_ASCII), 16));
+ position.set(Position.KEY_CID,
+ Integer.parseInt(data.readBytes(4).toString(StandardCharsets.US_ASCII), 16));
+ break;
+ case 'Q':
+ position.set("obd-pid", ChannelBuffers.hexDump(data));
+ break;
+ case 'R':
+ position.set("odb-travel", ChannelBuffers.hexDump(data));
+ break;
+ case 'S':
+ position.set("obd-traffic", ChannelBuffers.hexDump(data));
+ break;
+ default:
+ break;
+ }
+
}
if (position.getLatitude() != 0 && position.getLongitude() != 0) {
diff --git a/test/org/traccar/protocol/UproProtocolDecoderTest.java b/test/org/traccar/protocol/UproProtocolDecoderTest.java
index 711fe39b6..3af62da08 100644
--- a/test/org/traccar/protocol/UproProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/UproProtocolDecoderTest.java
@@ -10,39 +10,42 @@ public class UproProtocolDecoderTest extends ProtocolTest {
UproProtocolDecoder decoder = new UproProtocolDecoder(new UproProtocol());
- verifyPosition(decoder, text(
- "*MG201693502000035441,BA&A1213073325458307036690710000151116&P0730000032ce4fb3&D1&B0000000000&C005799?7&S3,20161115120025,07035.54659E,3324.87721N,3000,0,0,0,0,847,599,8,40,0,19,20&U_P\0\0\0\0\0\0\0\0\0\0\0\0\0\0&T0107#"));
+ verifyPosition(decoder, binary(
+ "2a4d473230303639333530323030303033353537332c42412641303834313237333332363334353230373033383933373630303030303235313131362642303130303030303030302647303036323030264d393930264e3235264f3035303026433030313a363b363926510411058c0c125c0d0a2fff4237ee614d66454c140826555f50000000000300000000000000000026543139333723"));
- verifyPosition(decoder, text(
- "*MG201693502000034964,AB&A0800253335360507036975710000091116&P0730000032d2a94d&B0000000000&N13&Z12&U_P\0\0\0\u0004\0\0\0\0\0\0\0\0\0\0#"),
+ verifyPosition(decoder, buffer(
+ "*MG201693502000035441,BA&A1213073325458307036690710000151116&P0730000032ce4fb3&D1&B0000000000&C005799?7&S3,20161115120025,07035.54659E,3324.87721N,3000,0,0,0,0,847,599,8,40,0,19,20&U_P\0\0\0\0\0\0\0\0\0\0\0\0\0\0&T0107"));
+
+ verifyPosition(decoder, buffer(
+ "*MG201693502000034964,AB&A0800253335360507036975710000091116&P0730000032d2a94d&B0000000000&N13&Z12&U_P\0\0\0\u0004\0\0\0\0\0\0\0\0\0\0"),
position("2016-11-09 08:00:25.000", true, -33.58934, -70.61626));
- verifyNothing(decoder, text(
- "*MG20113800138000,AH#"));
+ verifyNothing(decoder, buffer(
+ "*MG20113800138000,AH"));
- verifyPosition(decoder, text(
- "*MG201693502000034964,AB&A0200183324418107033792800009051116&B0000000000&N15&Z94&U_P\0\0\0\0\0\0\0\0\0\0\0\0\0\0#"));
+ verifyPosition(decoder, buffer(
+ "*MG201693502000034964,AB&A0200183324418107033792800009051116&B0000000000&N15&Z94&U_P\0\0\0\0\0\0\0\0\0\0\0\0\0\0"));
- verifyPosition(decoder, text(
- "*MG201693502000034964,AB&A0200543324412007033805910000051116&P0730000032d66785&B0000000000&N15&Z92&U_P\0\0\0\0\0\0\0\0\0\0\0\0\0\0#"));
+ verifyPosition(decoder, buffer(
+ "*MG201693502000034964,AB&A0200543324412007033805910000051116&P0730000032d66785&B0000000000&N15&Z92&U_P\0\0\0\0\0\0\0\0\0\0\0\0\0\0"));
- verifyPosition(decoder, text(
- "*AI2000905447674,BA&A2003064913201201845107561627121016&B0100000000&C05>8=961&F0333&K023101002154A7#"));
+ verifyPosition(decoder, buffer(
+ "*AI2000905447674,BA&A2003064913201201845107561627121016&B0100000000&C05>8=961&F0333&K023101002154A7"));
- verifyPosition(decoder, text(
- "*AI200905300036,AH&A0317264913209801844913060000251115&B0500000000&C0;4?72:9&F0000#"),
+ verifyPosition(decoder, buffer(
+ "*AI200905300036,AH&A0317264913209801844913060000251115&B0500000000&C0;4?72:9&F0000"),
position("2015-11-25 03:17:26.000", false, 49.22016, 18.74855));
- verifyPosition(decoder, text(
+ verifyPosition(decoder, buffer(
"*AI2000905300036,AS&A1647304913209801844913060000251115&B0400000000&C0;4?72:9&F0000"));
- verifyPosition(decoder, text(
+ verifyPosition(decoder, buffer(
"*AI2000905300036,AC1&A1648014913209801844913060000251115&B0400000000&C0;4?72:9&F0000"));
- verifyPosition(decoder, text(
- "*AI2000905300036,AB1&A1702464913231101844949860000251115&B0500000000&C0;4?72:9&F0000#"));
+ verifyPosition(decoder, buffer(
+ "*AI2000905300036,AB1&A1702464913231101844949860000251115&B0500000000&C0;4?72:9&F0000"));
- verifyPosition(decoder, text(
+ verifyPosition(decoder, buffer(
"*AI2000905300036,AD1&A1703054913231101844949860000251115&B0500000000&C0;4?72:9&F0000"));
}