diff options
4 files changed, 153 insertions, 66 deletions
diff --git a/src/main/java/org/traccar/protocol/CellocatorFrameDecoder.java b/src/main/java/org/traccar/protocol/CellocatorFrameDecoder.java index 7d5499d92..ee2adde6d 100644 --- a/src/main/java/org/traccar/protocol/CellocatorFrameDecoder.java +++ b/src/main/java/org/traccar/protocol/CellocatorFrameDecoder.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. @@ -46,11 +46,14 @@ public class CellocatorFrameDecoder extends BaseFrameDecoder { break; case CellocatorProtocolDecoder.MSG_CLIENT_SERIAL: if (buf.readableBytes() >= 19) { - length = 19 + buf.getUnsignedShortLE(16); + length = 19 + buf.getUnsignedShortLE(buf.readerIndex() + 16); } break; case CellocatorProtocolDecoder.MSG_CLIENT_MODULAR: - length = 15 + buf.getUnsignedByte(13); + length = 15 + buf.getUnsignedByte(buf.readerIndex() + 13); + break; + case CellocatorProtocolDecoder.MSG_CLIENT_MODULAR_EXT: + length = 16 + buf.getUnsignedShortLE(buf.readerIndex() + 13); break; default: break; diff --git a/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java index d23f76a93..f53c01234 100644 --- a/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java @@ -39,6 +39,7 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder { static final int MSG_CLIENT_SERIAL_LOG = 7; static final int MSG_CLIENT_SERIAL = 8; static final int MSG_CLIENT_MODULAR = 9; + static final int MSG_CLIENT_MODULAR_EXT = 11; public static final int MSG_SERVER_ACKNOWLEDGE = 4; @@ -82,93 +83,154 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder { } } - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + private Position decodeStatus(ByteBuf buf, DeviceSession deviceSession, boolean alternative) { - ByteBuf buf = (ByteBuf) msg; + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); - boolean alternative = buf.getByte(buf.readerIndex() + 3) != 'P'; + position.set(Position.KEY_VERSION_HW, buf.readUnsignedByte()); + position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); + buf.readUnsignedByte(); // protocol version - buf.skipBytes(4); // system code - int type = buf.readUnsignedByte(); - long deviceUniqueId = buf.readUnsignedIntLE(); + position.set(Position.KEY_STATUS, buf.readUnsignedByte() & 0x0f); - if (type != MSG_CLIENT_SERIAL) { - buf.readUnsignedShortLE(); // communication control + buf.readUnsignedByte(); // operator / configuration flags + buf.readUnsignedByte(); // reason data + position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + + position.set("mode", buf.readUnsignedByte()); + position.set(Position.KEY_INPUT, buf.readUnsignedIntLE()); + + if (alternative) { + buf.readUnsignedByte(); // input + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE()); + } else { + buf.readUnsignedByte(); // operator + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedIntLE()); } - byte packetNumber = buf.readByte(); - sendReply(channel, remoteAddress, deviceUniqueId, packetNumber); + position.set(Position.KEY_ODOMETER, buf.readUnsignedMediumLE()); - if (type == MSG_CLIENT_STATUS) { + buf.skipBytes(6); // multi-purpose data + buf.readUnsignedShortLE(); // fix time + buf.readUnsignedByte(); // location status + buf.readUnsignedByte(); // mode 1 + buf.readUnsignedByte(); // mode 2 - Position position = new Position(getProtocolName()); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceUniqueId)); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); + position.setValid(true); - position.set(Position.KEY_VERSION_HW, buf.readUnsignedByte()); - position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); - buf.readUnsignedByte(); // protocol version + if (alternative) { + position.setLongitude(buf.readIntLE() / 10000000.0); + position.setLatitude(buf.readIntLE() / 10000000.0); + } else { + position.setLongitude(buf.readIntLE() / Math.PI * 180 / 100000000); + position.setLatitude(buf.readIntLE() / Math.PI * 180 / 100000000); + } - position.set(Position.KEY_STATUS, buf.readUnsignedByte() & 0x0f); + position.setAltitude(buf.readIntLE() * 0.01); - buf.readUnsignedByte(); // operator / configuration flags - buf.readUnsignedByte(); // reason data - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + if (alternative) { + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedIntLE())); + position.setCourse(buf.readUnsignedShortLE() / 1000.0); + } else { + position.setSpeed(UnitsConverter.knotsFromMps(buf.readUnsignedIntLE() * 0.01)); + position.setCourse(buf.readUnsignedShortLE() / Math.PI * 180.0 / 1000.0); + } - position.set("mode", buf.readUnsignedByte()); - position.set(Position.KEY_INPUT, buf.readUnsignedIntLE()); + DateBuilder dateBuilder = new DateBuilder() + .setTimeReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedShortLE()); + position.setTime(dateBuilder.getDate()); + + return position; + } - if (alternative) { - buf.readUnsignedByte(); // input - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE()); - } else { - buf.readUnsignedByte(); // operator - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedIntLE()); + private Position decodeModular(ByteBuf buf, DeviceSession deviceSession) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedByte(); // packet control + buf.readUnsignedShortLE(); // length + buf.readUnsignedShortLE(); // reserved + buf.readUnsignedShortLE(); // reserved + + while (buf.readableBytes() > 3) { + + int moduleType = buf.readUnsignedByte(); + int endIndex = buf.readUnsignedShortLE() + buf.readerIndex(); + + switch (moduleType) { + case 2: + buf.readUnsignedShortLE(); // operator id + buf.readUnsignedIntLE(); // pl signature + int count = buf.readUnsignedByte(); + for (int i = 0; i < count; i++) { + int id = buf.readUnsignedShortLE(); + buf.readUnsignedByte(); // variable length + position.set(Position.PREFIX_IO + id, buf.readUnsignedIntLE()); + } + break; + case 6: + buf.readUnsignedByte(); // hdop + buf.readUnsignedByte(); // mode 1 + buf.readUnsignedByte(); // mode 2 + buf.readUnsignedByte(); // satellites + position.setLongitude(buf.readIntLE() / Math.PI * 180 / 100000000); + position.setLatitude(buf.readIntLE() / Math.PI * 180 / 100000000); + position.setAltitude(buf.readIntLE() * 0.01); + position.setSpeed(UnitsConverter.knotsFromMps(buf.readUnsignedByte() * 0.01)); + position.setCourse(buf.readUnsignedShortLE() / Math.PI * 180.0 / 1000.0); + break; + case 7: + buf.readUnsignedByte(); // valid + DateBuilder dateBuilder = new DateBuilder() + .setTimeReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + break; + default: + break; } - position.set(Position.KEY_ODOMETER, buf.readUnsignedMediumLE()); + buf.readerIndex(endIndex); - buf.skipBytes(6); // multi-purpose data - buf.readUnsignedShortLE(); // fix time - buf.readUnsignedByte(); // location status - buf.readUnsignedByte(); // mode 1 - buf.readUnsignedByte(); // mode 2 + } - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + return position; + } - position.setValid(true); + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - if (alternative) { - position.setLongitude(buf.readIntLE() / 10000000.0); - position.setLatitude(buf.readIntLE() / 10000000.0); - } else { - position.setLongitude(buf.readIntLE() / Math.PI * 180 / 100000000); - position.setLatitude(buf.readIntLE() / Math.PI * 180 / 100000000); - } + ByteBuf buf = (ByteBuf) msg; - position.setAltitude(buf.readIntLE() * 0.01); + boolean alternative = buf.getByte(buf.readerIndex() + 3) != 'P'; - if (alternative) { - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedIntLE())); - position.setCourse(buf.readUnsignedShortLE() / 1000.0); - } else { - position.setSpeed(UnitsConverter.knotsFromMps(buf.readUnsignedIntLE() * 0.01)); - position.setCourse(buf.readUnsignedShortLE() / Math.PI * 180.0 / 1000.0); - } + buf.skipBytes(4); // system code + int type = buf.readUnsignedByte(); - DateBuilder dateBuilder = new DateBuilder() - .setTimeReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedShortLE()); - position.setTime(dateBuilder.getDate()); + long deviceUniqueId = buf.readUnsignedIntLE(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceUniqueId)); + if (deviceSession == null) { + return null; + } + + if (type != MSG_CLIENT_SERIAL) { + buf.readUnsignedShortLE(); // communication control + } + byte packetNumber = buf.readByte(); - return position; + sendReply(channel, remoteAddress, deviceUniqueId, packetNumber); + + if (type == MSG_CLIENT_STATUS) { + return decodeStatus(buf, deviceSession, alternative); + } else if (type == MSG_CLIENT_MODULAR_EXT) { + return decodeModular(buf, deviceSession); } return null; diff --git a/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java b/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java new file mode 100644 index 000000000..914166a58 --- /dev/null +++ b/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java @@ -0,0 +1,19 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class CellocatorFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + CellocatorFrameDecoder decoder = new CellocatorFrameDecoder(); + + verifyFrame( + binary("4D4347500BA9880B00C80A7E003800000000000806000001210A14000613000000000D4457A5F71442AC02E80300000100040707000011171408060E1C08000100000200020000FD"), + decoder.decode(null, null, binary("4D4347500BA9880B00C80A7E003800000000000806000001210A14000613000000000D4457A5F71442AC02E80300000100040707000011171408060E1C08000100000200020000FD"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java index 769760fa5..d3066aa2d 100644 --- a/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class CellocatorProtocolDecoderTest extends ProtocolTest { CellocatorProtocolDecoder decoder = new CellocatorProtocolDecoder(null); verifyPosition(decoder, binary( + "4D4347500BA9880B00880A3900EE00000000000806000001210A140002B6001E0034419B1B1900400401000000014004000000000240046000000003400480000000044004DA0A0000054004000000000640045E000000074004310000000840042B000000094004870000000B4004B10B00000C4004590000000D40040000000010400465000000114004780C000012400465650700144004A4000000154004207F000016400400000000174004000000001E4004000000001F40040000000020400400000000214004000000002440040000000006130003040211D67DA4F7883AAF028403000001000007070001250A1004090E1905001E0001000062")); + + verifyPosition(decoder, binary( "4d4350470041420f000402021226d8a70221d801010000000001000000000000000000000000c4d90000000ca7a741ff0096dd15a40700000000000000001619130c01e307e4")); verifyPosition(decoder, binary( |