diff options
Diffstat (limited to 'src/org/traccar/protocol')
-rw-r--r-- | src/org/traccar/protocol/AplicomProtocolDecoder.java | 2 | ||||
-rw-r--r-- | src/org/traccar/protocol/GalileoProtocolDecoder.java | 234 | ||||
-rw-r--r-- | src/org/traccar/protocol/H02ProtocolDecoder.java | 26 | ||||
-rw-r--r-- | src/org/traccar/protocol/StarLinkProtocolDecoder.java | 159 | ||||
-rw-r--r-- | src/org/traccar/protocol/SuntechProtocolDecoder.java | 16 | ||||
-rw-r--r-- | src/org/traccar/protocol/UlbotechProtocolDecoder.java | 62 | ||||
-rw-r--r-- | src/org/traccar/protocol/Xt2400Protocol.java | 41 | ||||
-rw-r--r-- | src/org/traccar/protocol/Xt2400ProtocolDecoder.java | 187 |
8 files changed, 584 insertions, 143 deletions
diff --git a/src/org/traccar/protocol/AplicomProtocolDecoder.java b/src/org/traccar/protocol/AplicomProtocolDecoder.java index c07a656b3..03d7dbd6b 100644 --- a/src/org/traccar/protocol/AplicomProtocolDecoder.java +++ b/src/org/traccar/protocol/AplicomProtocolDecoder.java @@ -503,8 +503,6 @@ public class AplicomProtocolDecoder extends BaseProtocolDecoder { getLastLocation(position, null); - buf.readUnsignedShort(); // event - if ((selector & 0x0004) != 0) { buf.skipBytes(4); // snapshot time } diff --git a/src/org/traccar/protocol/GalileoProtocolDecoder.java b/src/org/traccar/protocol/GalileoProtocolDecoder.java index 64bfdd270..0e8163f8c 100644 --- a/src/org/traccar/protocol/GalileoProtocolDecoder.java +++ b/src/org/traccar/protocol/GalileoProtocolDecoder.java @@ -99,6 +99,134 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder { } } + private void decodeTag(Position position, ChannelBuffer buf, int tag) { + switch (tag) { + case 0x01: + position.set(Position.KEY_VERSION_HW, buf.readUnsignedByte()); + break; + case 0x02: + position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); + break; + case 0x04: + position.set("deviceId", buf.readUnsignedShort()); + break; + case 0x10: + position.set(Position.KEY_INDEX, buf.readUnsignedShort()); + break; + case 0x20: + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + break; + case 0x33: + position.setSpeed(buf.readUnsignedShort() * 0.0539957); + position.setCourse(buf.readUnsignedShort() * 0.1); + break; + case 0x34: + position.setAltitude(buf.readShort()); + break; + case 0x40: + position.set(Position.KEY_STATUS, buf.readUnsignedShort()); + break; + case 0x41: + position.set(Position.KEY_POWER, buf.readUnsignedShort()); + break; + case 0x42: + position.set(Position.KEY_BATTERY, buf.readUnsignedShort()); + break; + case 0x43: + position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); + break; + case 0x44: + position.set(Position.KEY_ACCELERATION, buf.readUnsignedInt()); + break; + case 0x45: + position.set(Position.KEY_OUTPUT, buf.readUnsignedShort()); + break; + case 0x46: + position.set(Position.KEY_INPUT, buf.readUnsignedShort()); + break; + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + position.set(Position.PREFIX_ADC + (tag - 0x50), buf.readUnsignedShort()); + break; + case 0x58: + position.set("rs2320", buf.readUnsignedShort()); + break; + case 0x59: + position.set("rs2321", buf.readUnsignedShort()); + break; + case 0xc0: + position.set("fuelTotal", buf.readUnsignedInt() * 0.5); + break; + case 0xc1: + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4); + position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedByte() - 40); + position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.125); + break; + case 0xc2: + position.set("canB0", buf.readUnsignedInt()); + break; + case 0xc3: + position.set("canB1", buf.readUnsignedInt()); + break; + case 0xc4: + case 0xc5: + case 0xc6: + case 0xc7: + case 0xc8: + case 0xc9: + case 0xca: + case 0xcb: + case 0xcc: + case 0xcd: + case 0xce: + case 0xcf: + case 0xd0: + case 0xd1: + case 0xd2: + position.set("can8Bit" + (tag - 0xc4), buf.readUnsignedByte()); + break; + case 0xd6: + case 0xd7: + case 0xd8: + case 0xd9: + case 0xda: + position.set("can16Bit" + (tag - 0xd6), buf.readUnsignedShort()); + break; + case 0xdb: + case 0xdc: + case 0xdd: + case 0xde: + case 0xdf: + position.set("can32Bit" + (tag - 0xdb), buf.readUnsignedInt()); + break; + case 0xd4: + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + break; + case 0xe2: + case 0xe3: + case 0xe4: + case 0xe5: + case 0xe6: + case 0xe7: + case 0xe8: + case 0xe9: + position.set("userData" + (tag - 0xe2), buf.readUnsignedInt()); + break; + case 0xea: + position.set("userDataArray", ChannelBuffers.hexDump(buf.readBytes(buf.readUnsignedByte()))); + break; + default: + buf.skipBytes(getTagLength(tag)); + break; + } + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -112,6 +240,7 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder { Set<Integer> tags = new HashSet<>(); boolean hasLocation = false; + DeviceSession deviceSession = null; Position position = new Position(); while (buf.readerIndex() < length) { @@ -128,97 +257,29 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder { } tags.add(tag); - switch (tag) { - case 0x01: - position.set(Position.KEY_VERSION_HW, buf.readUnsignedByte()); - break; - case 0x02: - position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); - break; - case 0x03: - getDeviceSession(channel, remoteAddress, buf.readBytes(15).toString(StandardCharsets.US_ASCII)); - break; - case 0x04: - position.set("deviceId", buf.readUnsignedShort()); - break; - case 0x10: - position.set(Position.KEY_INDEX, buf.readUnsignedShort()); - break; - case 0x20: - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - break; - case 0x30: - hasLocation = true; - position.setValid((buf.readUnsignedByte() & 0xf0) == 0x00); - position.setLatitude(buf.readInt() / 1000000.0); - position.setLongitude(buf.readInt() / 1000000.0); - break; - case 0x33: - position.setSpeed(buf.readUnsignedShort() * 0.0539957); - position.setCourse(buf.readUnsignedShort() * 0.1); - break; - case 0x34: - position.setAltitude(buf.readShort()); - break; - case 0x40: - position.set(Position.KEY_STATUS, buf.readUnsignedShort()); - break; - case 0x41: - position.set(Position.KEY_POWER, buf.readUnsignedShort()); - break; - case 0x42: - position.set(Position.KEY_BATTERY, buf.readUnsignedShort()); - break; - case 0x43: - position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); - break; - case 0x44: - position.set(Position.KEY_ACCELERATION, buf.readUnsignedInt()); - break; - case 0x45: - position.set(Position.KEY_OUTPUT, buf.readUnsignedShort()); - break; - case 0x46: - position.set(Position.KEY_INPUT, buf.readUnsignedShort()); - break; - case 0xd4: - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); - break; - case 0xc1: - position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4); - position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedByte() - 40); - position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.125); - break; - case 0x50: - position.set(Position.PREFIX_ADC + 0, buf.readUnsignedShort()); - break; - case 0x51: - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); - break; - case 0x52: - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); - break; - case 0x53: - position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort()); - break; - case 0xe2: - position.set("userData", buf.readUnsignedInt()); - break; - case 0xea: - position.set("userDataArray", ChannelBuffers.hexDump(buf.readBytes(buf.readUnsignedByte()))); - break; - default: - buf.skipBytes(getTagLength(tag)); - break; + if (tag == 0x03) { + deviceSession = getDeviceSession( + channel, remoteAddress, buf.readBytes(15).toString(StandardCharsets.US_ASCII)); + } else if (tag == 0x30) { + hasLocation = true; + position.setValid((buf.readUnsignedByte() & 0xf0) == 0x00); + position.setLatitude(buf.readInt() / 1000000.0); + position.setLongitude(buf.readInt() / 1000000.0); + } else { + decodeTag(position, buf, tag); } + } + if (hasLocation && position.getFixTime() != null) { positions.add(position); } - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); if (deviceSession == null) { - return null; + deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } } sendReply(channel, buf.readUnsignedShort()); @@ -228,10 +289,7 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder { p.setDeviceId(deviceSession.getDeviceId()); } - if (positions.isEmpty()) { - return null; - } - return positions; + return positions.isEmpty() ? null : positions; } } diff --git a/src/org/traccar/protocol/H02ProtocolDecoder.java b/src/org/traccar/protocol/H02ProtocolDecoder.java index 033ff3ba5..b11a1e0e6 100644 --- a/src/org/traccar/protocol/H02ProtocolDecoder.java +++ b/src/org/traccar/protocol/H02ProtocolDecoder.java @@ -73,6 +73,8 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ALARM, Position.ALARM_SOS); } else if (!BitUtil.check(status, 2)) { position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + } else if (!BitUtil.check(status, 19)) { + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); } position.set(Position.KEY_IGNITION, BitUtil.check(status, 10)); @@ -140,6 +142,7 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder { position.setCourse((buf.readUnsignedByte() & 0x0f) * 100.0 + BcdUtil.readInteger(buf, 2)); processStatus(position, buf.readUnsignedInt()); + return position; } @@ -168,7 +171,18 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder { .number("(?:(dd)(dd)(dd))?") // date (ddmmyy) .any() .number(",(x{8})") // status - .expression("(?:#|,.*)") + .groupBegin() + .number(",(d+),") // odometer + .number("(-?d+),") // temperature + .number("(d+.d+),") // fuel + .number("(-?d+),") // altitude + .number("(x+),") // lac + .number("(x+)#") // cid + .or() + .expression(",.*") + .or() + .text("#") + .groupEnd() .compile(); private static final Pattern PATTERN_NBR = new PatternBuilder() @@ -238,6 +252,16 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder { processStatus(position, parser.nextLong(16)); + if (parser.hasNext(6)) { + position.set(Position.KEY_ODOMETER, parser.nextInt()); + position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); + position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble()); + + position.setAltitude(parser.nextInt()); + + position.setNetwork(new Network(CellTower.fromLacCid(parser.nextInt(16), parser.nextInt(16)))); + } + return position; } diff --git a/src/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/org/traccar/protocol/StarLinkProtocolDecoder.java index 46d8ee9cc..eaee07870 100644 --- a/src/org/traccar/protocol/StarLinkProtocolDecoder.java +++ b/src/org/traccar/protocol/StarLinkProtocolDecoder.java @@ -17,8 +17,8 @@ package org.traccar.protocol; import org.jboss.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; import org.traccar.DeviceSession; -import org.traccar.helper.DateBuilder; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; import org.traccar.model.CellTower; @@ -26,12 +26,27 @@ import org.traccar.model.Network; import org.traccar.model.Position; import java.net.SocketAddress; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.TimeZone; import java.util.regex.Pattern; public class StarLinkProtocolDecoder extends BaseProtocolDecoder { + private String[] dataTags; + private DateFormat dateFormat; + public StarLinkProtocolDecoder(StarLinkProtocol protocol) { super(protocol); + + String format = Context.getConfig().getString( + getProtocolName() + ".format", "#EDT#,#EID#,#PDT#,#LAT#,#LONG#,#SPD#,#HEAD#,#ODO#," + + "#IN1#,#IN2#,#IN3#,#IN4#,#OUT1#,#OUT2#,#OUT3#,#OUT4#,#LAC#,#CID#,#VIN#,#VBAT#,#DEST#,#IGN#,#ENG#"); + dataTags = format.split(","); + + dateFormat = new SimpleDateFormat( + Context.getConfig().getString(getProtocolName() + ".dateFormat", "yyMMddHHmmss")); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); } private static final Pattern PATTERN = new PatternBuilder() @@ -40,23 +55,20 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder { .number("(x{6}|d{15}),") // id .number("(d+),") // type .number("(d+),") // index - .number("(dd)(dd)(dd)") // event date - .number("(dd)(dd)(dd),") // event time - .number("(d+),") // event - .number("(dd)(dd)(dd)") // fix date - .number("(dd)(dd)(dd),") // fix time - .number("([-+])(dd)(dd.d+),") // latitude - .number("([-+])(ddd)(dd.d+),") // longitude - .number("(d+.d+),") // speed - .number("(d+),") // course - .number("(d+),") // odometer - .number("(d+),") // lac - .number("(d+),") // cid - .number("(d+.d+),") // power - .number("(d+.d+)") // battery - .any() + .expression("(.+)") // data + .text("*") + .number("xx") // checksum .compile(); + public static final int MSG_EVENT_REPORT = 6; + + private double parseCoordinate(String value) { + int minutesIndex = value.indexOf('.') - 2; + double result = Double.parseDouble(value.substring(1, minutesIndex)); + result += Double.parseDouble(value.substring(minutesIndex)) / 60; + return value.charAt(0) == '+' ? result : -result; + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -71,38 +83,105 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder { return null; } + int type = parser.nextInt(); + if (type != MSG_EVENT_REPORT) { + return null; + } + Position position = new Position(); position.setProtocol(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - position.set(Position.KEY_TYPE, parser.nextInt()); position.set(Position.KEY_INDEX, parser.nextInt()); - DateBuilder dateBuilder = new DateBuilder() - .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt()) - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setDeviceTime(dateBuilder.getDate()); - - position.set(Position.KEY_EVENT, parser.nextInt()); - - dateBuilder = new DateBuilder() - .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt()) - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setFixTime(dateBuilder.getDate()); - - position.setValid(true); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - - position.setSpeed(parser.nextDouble()); - position.setCourse(parser.nextInt()); - - position.set(Position.KEY_ODOMETER, parser.nextInt()); + String[] data = parser.next().split(","); + Integer lac = null, cid = null; + int event = 0; + + for (int i = 0; i < Math.min(data.length, dataTags.length); i++) { + switch (dataTags[i]) { + case "#EDT#": + position.setDeviceTime(dateFormat.parse(data[i])); + break; + case "#EID#": + event = Integer.parseInt(data[i]); + position.set(Position.KEY_EVENT, event); + break; + case "#PDT#": + position.setFixTime(dateFormat.parse(data[i])); + break; + case "#LAT#": + position.setLatitude(parseCoordinate(data[i])); + break; + case "#LONG#": + position.setLongitude(parseCoordinate(data[i])); + break; + case "#SPD#": + position.setSpeed(Double.parseDouble(data[i])); + break; + case "#HEAD#": + position.setCourse(Integer.parseInt(data[i])); + break; + case "#ODO#": + position.set(Position.KEY_ODOMETER, Integer.parseInt(data[i])); + break; + case "#IN1#": + position.set(Position.PREFIX_IN + 1, Integer.parseInt(data[i])); + break; + case "#IN2#": + position.set(Position.PREFIX_IN + 2, Integer.parseInt(data[i])); + break; + case "#IN3#": + position.set(Position.PREFIX_IN + 3, Integer.parseInt(data[i])); + break; + case "#IN4#": + position.set(Position.PREFIX_IN + 4, Integer.parseInt(data[i])); + break; + case "#OUT1#": + position.set(Position.PREFIX_OUT + 1, Integer.parseInt(data[i])); + break; + case "#OUT2#": + position.set(Position.PREFIX_OUT + 2, Integer.parseInt(data[i])); + break; + case "#OUT3#": + position.set(Position.PREFIX_OUT + 3, Integer.parseInt(data[i])); + break; + case "#OUT4#": + position.set(Position.PREFIX_OUT + 4, Integer.parseInt(data[i])); + break; + case "#LAC#": + lac = Integer.parseInt(data[i]); + break; + case "#CID#": + cid = Integer.parseInt(data[i]); + break; + case "#VIN#": + position.set(Position.KEY_POWER, Double.parseDouble(data[i])); + break; + case "#VBAT#": + position.set(Position.KEY_BATTERY, Double.parseDouble(data[i])); + break; + case "#DEST#": + position.set("destination", data[i]); + break; + case "#IGN#": + position.set(Position.KEY_IGNITION, data[i].equals("1")); + break; + case "#ENG#": + position.set("engine", data[i].equals("1")); + break; + default: + break; + } + } - position.setNetwork(new Network(CellTower.fromLacCid(parser.nextInt(), parser.nextInt()))); + if (lac != null && cid != null) { + position.setNetwork(new Network(CellTower.fromLacCid(lac, cid))); + } - position.set(Position.KEY_POWER, parser.nextDouble()); - position.set(Position.KEY_BATTERY, parser.nextDouble()); + if (event == 20) { + position.set(Position.KEY_RFID, data[data.length - 1]); + } return position; } diff --git a/src/org/traccar/protocol/SuntechProtocolDecoder.java b/src/org/traccar/protocol/SuntechProtocolDecoder.java index 55d5c224a..e19335cb0 100644 --- a/src/org/traccar/protocol/SuntechProtocolDecoder.java +++ b/src/org/traccar/protocol/SuntechProtocolDecoder.java @@ -31,11 +31,13 @@ import java.util.TimeZone; public class SuntechProtocolDecoder extends BaseProtocolDecoder { private int protocolType; + private boolean hbm; public SuntechProtocolDecoder(SuntechProtocol protocol) { super(protocol); protocolType = Context.getConfig().getInteger(getProtocolName() + ".protocolType"); + hbm = Context.getConfig().getBoolean(getProtocolName() + ".hbm"); } public void setProtocolType(int protocolType) { @@ -144,12 +146,16 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_INDEX, Integer.parseInt(values[index++])); } - if (index < values.length) { - position.set(Position.KEY_HOURS, Integer.parseInt(values[index++])); - } + if (hbm) { + + if (index < values.length) { + position.set(Position.KEY_HOURS, Integer.parseInt(values[index++])); + } + + if (index < values.length) { + position.set(Position.KEY_BATTERY, Double.parseDouble(values[index])); + } - if (index < values.length) { - position.set(Position.KEY_BATTERY, Double.parseDouble(values[index])); } return position; diff --git a/src/org/traccar/protocol/UlbotechProtocolDecoder.java b/src/org/traccar/protocol/UlbotechProtocolDecoder.java index 19e9cd5e9..97912e128 100644 --- a/src/org/traccar/protocol/UlbotechProtocolDecoder.java +++ b/src/org/traccar/protocol/UlbotechProtocolDecoder.java @@ -22,7 +22,10 @@ import org.traccar.BaseProtocolDecoder; import org.traccar.Context; import org.traccar.DeviceSession; import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; import org.traccar.helper.ObdDecoder; +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; @@ -31,6 +34,7 @@ import org.traccar.model.Position; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.util.Date; +import java.util.regex.Pattern; public class UlbotechProtocolDecoder extends BaseProtocolDecoder { @@ -161,27 +165,58 @@ public class UlbotechProtocolDecoder extends BaseProtocolDecoder { } } - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + private static final Pattern PATTERN = new PatternBuilder() + .text("*TS") + .number("dd,") // protocol version + .number("(d{15}),") // device id + .number("(dd)(dd)(dd)") // time + .number("(dd)(dd)(dd),") // date + .expression("([^#]+)") // command + .text("#") + .compile(); - ChannelBuffer buf = (ChannelBuffer) msg; + private Object decodeText(Channel channel, SocketAddress remoteAddress, String sentence) { - if (buf.readUnsignedByte() != 0xF8) { + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { return null; } - buf.readUnsignedByte(); // version - buf.readUnsignedByte(); // type + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } Position position = new Position(); position.setProtocol(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()) + .setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + getLastLocation(position, dateBuilder.getDate()); + + position.set(Position.KEY_RESULT, parser.next()); + + return position; + } + + private Object decodeBinary(Channel channel, SocketAddress remoteAddress, ChannelBuffer buf) { + + buf.readUnsignedByte(); // header + buf.readUnsignedByte(); // version + buf.readUnsignedByte(); // type String imei = ChannelBuffers.hexDump(buf.readBytes(8)).substring(1); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); if (deviceSession == null) { return null; } + + Position position = new Position(); + position.setProtocol(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); long seconds = buf.readUnsignedInt() & 0x7fffffffL; @@ -298,4 +333,17 @@ public class UlbotechProtocolDecoder extends BaseProtocolDecoder { return position; } + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ChannelBuffer buf = (ChannelBuffer) msg; + + if (buf.getUnsignedByte(buf.readerIndex()) == 0xF8) { + return decodeBinary(channel, remoteAddress, buf); + } else { + return decodeText(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII)); + } + } + } diff --git a/src/org/traccar/protocol/Xt2400Protocol.java b/src/org/traccar/protocol/Xt2400Protocol.java new file mode 100644 index 000000000..0c5e9cd4c --- /dev/null +++ b/src/org/traccar/protocol/Xt2400Protocol.java @@ -0,0 +1,41 @@ +/* + * Copyright 2017 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 org.jboss.netty.bootstrap.ConnectionlessBootstrap; +import org.jboss.netty.channel.ChannelPipeline; +import org.traccar.BaseProtocol; +import org.traccar.TrackerServer; + +import java.util.List; + +public class Xt2400Protocol extends BaseProtocol { + + public Xt2400Protocol() { + super("xt2400"); + } + + @Override + public void initTrackerServers(List<TrackerServer> serverList) { + serverList.add(new TrackerServer(new ConnectionlessBootstrap(), getName()) { + @Override + protected void addSpecificHandlers(ChannelPipeline pipeline) { + pipeline.addLast("objectDecoder", new Xt2400ProtocolDecoder(Xt2400Protocol.this)); + } + }); + } + +} diff --git a/src/org/traccar/protocol/Xt2400ProtocolDecoder.java b/src/org/traccar/protocol/Xt2400ProtocolDecoder.java new file mode 100644 index 000000000..a42c6175f --- /dev/null +++ b/src/org/traccar/protocol/Xt2400ProtocolDecoder.java @@ -0,0 +1,187 @@ +/* + * Copyright 2017 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 org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import javax.xml.bind.DatatypeConverter; +import java.net.SocketAddress; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Xt2400ProtocolDecoder extends BaseProtocolDecoder { + + public Xt2400ProtocolDecoder(Xt2400Protocol protocol) { + super(protocol); + + String config = Context.getConfig().getString(getProtocolName() + ".config"); + if (config != null) { + setConfig(config); + } + } + + private static final Map<Integer, Integer> TAG_LENGTH_MAP = new HashMap<>(); + + static { + int[] l1 = { + 0x01, 0x02, 0x04, 0x0b, 0x0c, 0x0d, 0x12, 0x13, + 0x16, 0x17, 0x1c, 0x1f, 0x23, 0x2c, 0x2d, 0x30, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x40, 0x41, + 0x53, 0x66, 0x69, 0x6a, 0x93, 0x94, 0x96 + }; + int[] l2 = { + 0x05, 0x09, 0x0a, 0x14, 0x15, 0x1d, 0x1e, 0x24, + 0x26, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x57, 0x58, 0x59, 0x5a, 0x6b, 0x6f, 0x7A, + 0x7B, 0x7C, 0x7d, 0x7E, 0x7F, 0x80, 0x81, 0x82, + 0x83, 0x84, 0x85, 0x86 + }; + int[] l4 = { + 0x03, 0x06, 0x07, 0x08, 0x0e, 0x0f, 0x10, 0x11, + 0x18, 0x19, 0x1a, 0x1b, 0x20, 0x21, 0x22, 0x2e, + 0x2f, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x54, 0x55, 0x56, 0x5b, 0x5c, 0x5d, + 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x68, 0x6e, 0x71, + 0x72, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d + }; + for (int i : l1) { + TAG_LENGTH_MAP.put(i, 1); + } + for (int i : l2) { + TAG_LENGTH_MAP.put(i, 2); + } + for (int i : l4) { + TAG_LENGTH_MAP.put(i, 4); + } + TAG_LENGTH_MAP.put(0x65, 17); + TAG_LENGTH_MAP.put(0x73, 16); + TAG_LENGTH_MAP.put(0x95, 24); + } + + private static int getTagLength(int tag) { + Integer length = TAG_LENGTH_MAP.get(tag); + if (length == null) { + throw new IllegalArgumentException("Unknown tag: " + tag); + } + return length; + } + + private Map<Short, byte[]> formats = new HashMap<>(); + + public void setConfig(String configString) { + Pattern pattern = Pattern.compile(":wycfg pcr\\[\\d+\\] ([0-9a-fA-F]{2})[0-9a-fA-F]{2}([0-9a-fA-F]+)"); + Matcher matcher = pattern.matcher(configString); + while (matcher.find()) { + formats.put(Short.parseShort(matcher.group(1), 16), DatatypeConverter.parseHexBinary(matcher.group(2))); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ChannelBuffer buf = (ChannelBuffer) msg; + + byte[] format = null; + if (formats.size() > 1) { + format = formats.get(buf.getUnsignedByte(buf.readerIndex())); + } else if (!formats.isEmpty()) { + format = formats.values().iterator().next(); + } + + if (format == null) { + return null; + } + + Position position = new Position(); + position.setProtocol(getProtocolName()); + + for (byte tag : format) { + switch ((int) tag) { + case 0x03: + DeviceSession deviceSession = getDeviceSession( + channel, remoteAddress, String.valueOf(buf.readUnsignedInt())); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + break; + case 0x04: + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + break; + case 0x05: + position.set(Position.KEY_INDEX, buf.readUnsignedShort()); + break; + case 0x06: + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + break; + case 0x07: + position.setLatitude(buf.readInt() * 0.000001); + break; + case 0x08: + position.setLongitude(buf.readInt() * 0.000001); + break; + case 0x09: + position.setAltitude(buf.readShort() * 0.1); + break; + case 0x0a: + position.setCourse(buf.readShort() * 0.1); + break; + case 0x0b: + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + break; + case 0x10: + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt()); + break; + case 0x12: + position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); + break; + case 0x13: + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + break; + case 0x16: + position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.1); + break; + case 0x17: + position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.1); + break; + default: + buf.skipBytes(getTagLength(tag)); + break; + } + } + + if (position.getLatitude() != 0 && position.getLongitude() != 0) { + position.setValid(true); + } else { + getLastLocation(position, position.getDeviceTime()); + } + + return position; + } + +} |