From a58b40a49e96f8fc876b88b6b10489f8532893d9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 10 Mar 2018 16:23:06 +1300 Subject: Replace deprecated classes --- src/org/traccar/helper/DataConverter.java | 47 +++++++++++++++++++++++++++++++ src/org/traccar/helper/Hashing.java | 9 +++--- 2 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 src/org/traccar/helper/DataConverter.java (limited to 'src/org/traccar/helper') diff --git a/src/org/traccar/helper/DataConverter.java b/src/org/traccar/helper/DataConverter.java new file mode 100644 index 000000000..7abd4ae93 --- /dev/null +++ b/src/org/traccar/helper/DataConverter.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018 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.helper; + +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.Hex; + +public final class DataConverter { + + private DataConverter() { + } + + public static byte[] parseHex(String string) { + try { + return Hex.decodeHex(string); + } catch (DecoderException e) { + throw new RuntimeException(e); + } + } + + public static String printHex(byte[] data) { + return Hex.encodeHexString(data); + } + + public static byte[] parseBase64(String string) { + return Base64.decodeBase64(string); + } + + public static String printBase64(byte[] data) { + return Base64.encodeBase64String(data); + } + +} diff --git a/src/org/traccar/helper/Hashing.java b/src/org/traccar/helper/Hashing.java index 3fcc124fa..e91310eda 100644 --- a/src/org/traccar/helper/Hashing.java +++ b/src/org/traccar/helper/Hashing.java @@ -17,7 +17,6 @@ package org.traccar.helper; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; -import javax.xml.bind.DatatypeConverter; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; @@ -75,13 +74,13 @@ public final class Hashing { RANDOM.nextBytes(salt); byte[] hash = function(password.toCharArray(), salt); return new HashingResult( - DatatypeConverter.printHexBinary(hash), - DatatypeConverter.printHexBinary(salt)); + DataConverter.printHex(hash), + DataConverter.printHex(salt)); } public static boolean validatePassword(String password, String hashHex, String saltHex) { - byte[] hash = DatatypeConverter.parseHexBinary(hashHex); - byte[] salt = DatatypeConverter.parseHexBinary(saltHex); + byte[] hash = DataConverter.parseHex(hashHex); + byte[] salt = DataConverter.parseHex(saltHex); return slowEquals(hash, function(password.toCharArray(), salt)); } -- cgit v1.2.3 From d8bbc2b6e8c1e7447f3e317747982b3c6362c66d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 12 Mar 2018 05:21:58 +1300 Subject: Add new OBD PID parameters --- src/org/traccar/helper/ObdDecoder.java | 31 +++++++++------------- .../protocol/CastelProtocolDecoderTest.java | 3 +++ 2 files changed, 16 insertions(+), 18 deletions(-) (limited to 'src/org/traccar/helper') diff --git a/src/org/traccar/helper/ObdDecoder.java b/src/org/traccar/helper/ObdDecoder.java index 4bc3bcdfb..1bdcce352 100644 --- a/src/org/traccar/helper/ObdDecoder.java +++ b/src/org/traccar/helper/ObdDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2018 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. @@ -29,15 +29,6 @@ public final class ObdDecoder { private static final int MODE_FREEZE_FRAME = 0x02; private static final int MODE_CODES = 0x03; - private static final int PID_ENGINE_LOAD = 0x04; - private static final int PID_COOLANT_TEMPERATURE = 0x05; - private static final int PID_ENGINE_RPM = 0x0C; - private static final int PID_VEHICLE_SPEED = 0x0D; - private static final int PID_THROTTLE_POSITION = 0x11; - private static final int PID_MIL_DISTANCE = 0x21; - private static final int PID_FUEL_LEVEL = 0x2F; - private static final int PID_DISTANCE_CLEARED = 0x31; - public static Map.Entry decode(int mode, String value) { switch (mode) { case MODE_CURRENT: @@ -86,21 +77,25 @@ public final class ObdDecoder { public static Map.Entry decodeData(int pid, int value, boolean convert) { switch (pid) { - case PID_ENGINE_LOAD: + case 0x04: return createEntry(Position.KEY_ENGINE_LOAD, convert ? value * 100 / 255 : value); - case PID_COOLANT_TEMPERATURE: + case 0x05: return createEntry(Position.KEY_COOLANT_TEMP, convert ? value - 40 : value); - case PID_ENGINE_RPM: + case 0x0B: + return createEntry("mapIntake", value); + case 0x0C: return createEntry(Position.KEY_RPM, convert ? value / 4 : value); - case PID_VEHICLE_SPEED: + case 0x0D: return createEntry(Position.KEY_OBD_SPEED, value); - case PID_THROTTLE_POSITION: + case 0x0F: + return createEntry("intakeTemp", convert ? value - 40 : value); + case 0x11: return createEntry(Position.KEY_THROTTLE, convert ? value * 100 / 255 : value); - case PID_MIL_DISTANCE: + case 0x21: return createEntry("milDistance", value); - case PID_FUEL_LEVEL: + case 0x2F: return createEntry(Position.KEY_FUEL_LEVEL, convert ? value * 100 / 255 : value); - case PID_DISTANCE_CLEARED: + case 0x31: return createEntry("clearedDistance", value); default: return null; diff --git a/test/org/traccar/protocol/CastelProtocolDecoderTest.java b/test/org/traccar/protocol/CastelProtocolDecoderTest.java index 2dccf4a0a..cb44087a1 100644 --- a/test/org/traccar/protocol/CastelProtocolDecoderTest.java +++ b/test/org/traccar/protocol/CastelProtocolDecoderTest.java @@ -12,6 +12,9 @@ public class CastelProtocolDecoderTest extends ProtocolTest { CastelProtocolDecoder decoder = new CastelProtocolDecoder(new CastelProtocol()); + verifyAttributes(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "4040560004323133474c3230313630303033363400000000004002a122a05a5423a05abe0f2a000000000007f1f90014000000040001640011170003001e000505210b210c210d210f2101062b58ef02001a25950d0a")); + verifyAttributes(decoder, binary(ByteOrder.LITTLE_ENDIAN, "404057000431303031313132353239393837000000000000004002C1F06952F0F169529C9111000000000069830000470000000400036401014C01030078000505210C210D210F21102101073BE8030064280AEB930D0A")); -- cgit v1.2.3 From d847f80334498bde6993b8f3a38c7df05d83b47b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 26 Mar 2018 06:45:10 +1300 Subject: Implement EGTS responses --- src/org/traccar/helper/Checksum.java | 35 +++++++ src/org/traccar/protocol/EgtsProtocol.java | 7 +- src/org/traccar/protocol/EgtsProtocolDecoder.java | 109 ++++++++++++++++++--- .../traccar/protocol/EgtsProtocolDecoderTest.java | 3 + 4 files changed, 136 insertions(+), 18 deletions(-) (limited to 'src/org/traccar/helper') diff --git a/src/org/traccar/helper/Checksum.java b/src/org/traccar/helper/Checksum.java index 43ba6a689..c4141e7d2 100644 --- a/src/org/traccar/helper/Checksum.java +++ b/src/org/traccar/helper/Checksum.java @@ -129,6 +129,33 @@ public final class Checksum { 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040, }; + private static final int[] CRC8_TABLE = { + 0x00, 0x31, 0x62, 0x53, 0xC4, 0xF5, 0xA6, 0x97, + 0xB9, 0x88, 0xDB, 0xEA, 0x7D, 0x4C, 0x1F, 0x2E, + 0x43, 0x72, 0x21, 0x10, 0x87, 0xB6, 0xE5, 0xD4, + 0xFA, 0xCB, 0x98, 0xA9, 0x3E, 0x0F, 0x5C, 0x6D, + 0x86, 0xB7, 0xE4, 0xD5, 0x42, 0x73, 0x20, 0x11, 0x3F, + 0x0E, 0x5D, 0x6C, 0xFB, 0xCA, 0x99, 0xA8, 0xC5, 0xF4, 0xA7, 0x96, + 0x01, 0x30, 0x63, 0x52, 0x7C, 0x4D, 0x1E, 0x2F, 0xB8, 0x89, 0xDA, + 0xEB, 0x3D, 0x0C, 0x5F, 0x6E, 0xF9, 0xC8, 0x9B, 0xAA, 0x84, 0xB5, + 0xE6, 0xD7, 0x40, 0x71, 0x22, 0x13, 0x7E, 0x4F, 0x1C, 0x2D, 0xBA, + 0x8B, 0xD8, 0xE9, 0xC7, 0xF6, 0xA5, 0x94, 0x03, 0x32, 0x61, 0x50, + 0xBB, 0x8A, 0xD9, 0xE8, 0x7F, 0x4E, 0x1D, 0x2C, 0x02, 0x33, 0x60, + 0x51, 0xC6, 0xF7, 0xA4, 0x95, 0xF8, 0xC9, 0x9A, 0xAB, 0x3C, 0x0D, + 0x5E, 0x6F, 0x41, 0x70, 0x23, 0x12, 0x85, 0xB4, 0xE7, 0xD6, 0x7A, + 0x4B, 0x18, 0x29, 0xBE, 0x8F, 0xDC, 0xED, 0xC3, 0xF2, 0xA1, 0x90, + 0x07, 0x36, 0x65, 0x54, 0x39, 0x08, 0x5B, 0x6A, 0xFD, 0xCC, 0x9F, + 0xAE, 0x80, 0xB1, 0xE2, 0xD3, 0x44, 0x75, 0x26, 0x17, 0xFC, 0xCD, + 0x9E, 0xAF, 0x38, 0x09, 0x5A, 0x6B, 0x45, 0x74, 0x27, 0x16, 0x81, + 0xB0, 0xE3, 0xD2, 0xBF, 0x8E, 0xDD, 0xEC, 0x7B, 0x4A, 0x19, 0x28, + 0x06, 0x37, 0x64, 0x55, 0xC2, 0xF3, 0xA0, 0x91, 0x47, 0x76, 0x25, + 0x14, 0x83, 0xB2, 0xE1, 0xD0, 0xFE, 0xCF, 0x9C, 0xAD, 0x3A, 0x0B, + 0x58, 0x69, 0x04, 0x35, 0x66, 0x57, 0xC0, 0xF1, 0xA2, 0x93, 0xBD, + 0x8C, 0xDF, 0xEE, 0x79, 0x48, 0x1B, 0x2A, 0xC1, 0xF0, 0xA3, 0x92, + 0x05, 0x34, 0x67, 0x56, 0x78, 0x49, 0x1A, 0x2B, 0xBC, 0x8D, 0xDE, + 0xEF, 0x82, 0xB3, 0xE0, 0xD1, 0x46, 0x77, 0x24, 0x15, 0x3B, 0x0A, + 0x59, 0x68, 0xFF, 0xCE, 0x9D, 0xAC }; + // More info: http://reveng.sourceforge.net/crc-catalogue/16.htm public static final String CRC16_IBM = "IBM"; public static final String CRC16_MODBUS = "MODBUS"; @@ -181,6 +208,14 @@ public final class Checksum { } } + public static int crc8(ByteBuffer buf) { + int crc = 0xFF; + while (buf.hasRemaining()) { + crc = CRC8_TABLE[(crc ^ buf.get()) & 0xFF]; + } + return crc & 0xFF; + } + public static int crc32(ByteBuffer buf) { CRC32 checksum = new CRC32(); while (buf.hasRemaining()) { diff --git a/src/org/traccar/protocol/EgtsProtocol.java b/src/org/traccar/protocol/EgtsProtocol.java index 0a57f0061..13ec6c9a7 100644 --- a/src/org/traccar/protocol/EgtsProtocol.java +++ b/src/org/traccar/protocol/EgtsProtocol.java @@ -20,6 +20,7 @@ import org.jboss.netty.channel.ChannelPipeline; import org.traccar.BaseProtocol; import org.traccar.TrackerServer; +import java.nio.ByteOrder; import java.util.List; public class EgtsProtocol extends BaseProtocol { @@ -30,13 +31,15 @@ public class EgtsProtocol extends BaseProtocol { @Override public void initTrackerServers(List serverList) { - serverList.add(new TrackerServer(new ServerBootstrap(), getName()) { + TrackerServer server = new TrackerServer(new ServerBootstrap(), getName()) { @Override protected void addSpecificHandlers(ChannelPipeline pipeline) { pipeline.addLast("frameDecoder", new EgtsFrameDecoder()); pipeline.addLast("objectDecoder", new EgtsProtocolDecoder(EgtsProtocol.this)); } - }); + }; + server.setEndianness(ByteOrder.LITTLE_ENDIAN); + serverList.add(server); } } diff --git a/src/org/traccar/protocol/EgtsProtocolDecoder.java b/src/org/traccar/protocol/EgtsProtocolDecoder.java index d05504d81..85376b1a5 100644 --- a/src/org/traccar/protocol/EgtsProtocolDecoder.java +++ b/src/org/traccar/protocol/EgtsProtocolDecoder.java @@ -16,13 +16,17 @@ 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; import org.traccar.helper.BitUtil; +import org.traccar.helper.Checksum; import org.traccar.model.Position; import java.net.SocketAddress; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.LinkedList; import java.util.List; @@ -33,6 +37,10 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder { super(protocol); } + public static final int PT_RESPONSE = 0; + public static final int PT_APPDATA = 1; + public static final int PT_SIGNED_APPDATA = 2; + public static final int SERVICE_AUTH = 1; public static final int SERVICE_TELEDATA = 2; public static final int SERVICE_COMMANDS = 4; @@ -60,6 +68,44 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_LIQUID_LEVEL_SENSOR = 27; public static final int MSG_PASSENGERS_COUNTERS = 28; + private int packetId; + + private void sendResponse( + Channel channel, int packetType, int index, int serviceType, int type, ChannelBuffer content) { + if (channel != null) { + + ChannelBuffer data = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0); + data.writeByte(type); + data.writeShort(content.readableBytes()); + data.writeBytes(content); + + ChannelBuffer record = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0); + record.writeShort(data.readableBytes()); + record.writeShort(index); + record.writeByte(1 << 6); // flags + record.writeByte(serviceType); + record.writeByte(serviceType); + record.writeBytes(data); + int recordChecksum = Checksum.crc16(Checksum.CRC16_CCITT_FALSE, record.toByteBuffer()); + + ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0); + response.writeByte(1); // protocol version + response.writeByte(0); // security key id + response.writeByte(0); // flags + response.writeByte(5 + 2 + 2 + 2); // header length + response.writeByte(0); // encoding + response.writeShort(record.readableBytes()); + response.writeShort(packetId++); + response.writeByte(packetType); + response.writeByte(Checksum.crc8(response.toByteBuffer())); + response.writeBytes(record); + response.writeShort(recordChecksum); + + channel.write(response); + + } + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -68,26 +114,16 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder { buf.skipBytes(buf.getUnsignedByte(buf.readerIndex() + 3)); - DeviceSession deviceSession = null; List positions = new LinkedList<>(); while (buf.readableBytes() > 2) { int length = buf.readUnsignedShort(); - - buf.readUnsignedShort(); // index - + int index = buf.readUnsignedShort(); int recordFlags = buf.readUnsignedByte(); if (BitUtil.check(recordFlags, 0)) { - String deviceId = String.valueOf(buf.readUnsignedInt()); - if (deviceSession == null) { - deviceSession = getDeviceSession(channel, remoteAddress, deviceId); - } - } - - if (deviceSession == null) { - deviceSession = getDeviceSession(channel, remoteAddress); + buf.readUnsignedInt(); // object id } if (BitUtil.check(recordFlags, 1)) { @@ -97,19 +133,58 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder { buf.readUnsignedInt(); // time } - buf.readUnsignedByte(); // source service type + int serviceType = buf.readUnsignedByte(); buf.readUnsignedByte(); // recipient service type int recordEnd = buf.readerIndex() + length; Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession != null) { + position.setDeviceId(deviceSession.getDeviceId()); + } + + ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0); + response.writeShort(index); + response.writeByte(0); // success + sendResponse(channel, PT_RESPONSE, index, serviceType, MSG_RECORD_RESPONSE, response); while (buf.readerIndex() < recordEnd) { int type = buf.readUnsignedByte(); int end = buf.readUnsignedShort() + buf.readerIndex(); - if (type == MSG_POS_DATA) { + if (type == MSG_TERM_IDENTITY) { + + buf.readUnsignedInt(); // object id + int flags = buf.readUnsignedByte(); + + if (BitUtil.check(flags, 0)) { + buf.readUnsignedShort(); // home dispatcher identifier + } + if (BitUtil.check(flags, 1)) { + getDeviceSession(channel, remoteAddress, buf.readBytes(15).toString(StandardCharsets.US_ASCII)); + } + if (BitUtil.check(flags, 2)) { + getDeviceSession(channel, remoteAddress, buf.readBytes(16).toString(StandardCharsets.US_ASCII)); + } + if (BitUtil.check(flags, 3)) { + buf.skipBytes(3); // language identifier + } + if (BitUtil.check(flags, 5)) { + buf.skipBytes(3); // network identifier + } + if (BitUtil.check(flags, 6)) { + buf.readUnsignedShort(); // buffer size + } + if (BitUtil.check(flags, 7)) { + getDeviceSession(channel, remoteAddress, buf.readBytes(15).toString(StandardCharsets.US_ASCII)); + } + + response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0); + response.writeByte(0); // success + sendResponse(channel, PT_APPDATA, index, serviceType, MSG_RESULT_CODE, response); + + } else if (type == MSG_POS_DATA) { position.setTime(new Date((buf.readUnsignedInt() + 1262304000) * 1000)); // since 2010-01-01 position.setLatitude(buf.readUnsignedInt() * 90.0 / 0xFFFFFFFFL); @@ -166,7 +241,9 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder { buf.readerIndex(end); } - positions.add(position); + if (deviceSession != null) { + positions.add(position); + } } return positions.isEmpty() ? null : positions; diff --git a/test/org/traccar/protocol/EgtsProtocolDecoderTest.java b/test/org/traccar/protocol/EgtsProtocolDecoderTest.java index 9a3434bec..7e5720b39 100644 --- a/test/org/traccar/protocol/EgtsProtocolDecoderTest.java +++ b/test/org/traccar/protocol/EgtsProtocolDecoderTest.java @@ -12,6 +12,9 @@ public class EgtsProtocolDecoderTest extends ProtocolTest { EgtsProtocolDecoder decoder = new EgtsProtocolDecoder(new EgtsProtocol()); + verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "0100000b002400a0d601f01900030081030000000101011600030000004238363434393530333436343333373600014cdc")); + verifyPositions(decoder, binary(ByteOrder.LITTLE_ENDIAN, "0100020B0025003A5701C91A003A5701CD6E68490202101700CBB4740F7617FD924364104F116A0000000000010300001EC2"), position("2018-03-21 05:38:19.000", true, 51.67569, 55.59189)); -- cgit v1.2.3 From f2d31534703eb7b56a4c1ce82d354fcbb4254266 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 27 Mar 2018 05:53:40 +1300 Subject: Reimplement CRC8 and CRC16 calculation --- src/org/traccar/helper/Checksum.java | 265 +++++++--------------- src/org/traccar/protocol/EgtsProtocolDecoder.java | 2 +- test/org/traccar/helper/ChecksumTest.java | 15 +- 3 files changed, 100 insertions(+), 182 deletions(-) (limited to 'src/org/traccar/helper') diff --git a/src/org/traccar/helper/Checksum.java b/src/org/traccar/helper/Checksum.java index c4141e7d2..5aed84bf8 100644 --- a/src/org/traccar/helper/Checksum.java +++ b/src/org/traccar/helper/Checksum.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2015 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2018 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. @@ -24,198 +24,109 @@ public final class Checksum { private Checksum() { } - private static final int[] CRC16_CCITT_TABLE_REVERSE = { - 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, - 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, - 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, - 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, - 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, - 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, - 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, - 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, - 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, - 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, - 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, - 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, - 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, - 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, - 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, - 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, - 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, - 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, - 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, - 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, - 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, - 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, - 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, - 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, - 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, - 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, - 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, - 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, - 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, - 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, - 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, - 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 - }; - - private static final int[] CRC16_CCITT_TABLE = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, - 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, - 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, - 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, - 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, - 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, - 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, - 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, - 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, - 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, - 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, - 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, - 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, - 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, - 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, - 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, - 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, - 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, - 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, - 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, - 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, - 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, - 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 - }; + public static class Algorithm { + + private int poly; + private int init; + private boolean refIn; + private boolean refOut; + private int xorOut; + private int[] table; + + public Algorithm(int bits, int poly, int init, boolean refIn, boolean refOut, int xorOut) { + this.poly = poly; + this.init = init; + this.refIn = refIn; + this.refOut = refOut; + this.xorOut = xorOut; + this.table = bits == 8 ? initTable8() : initTable16(); + } - private static final int[] CRC16_IBM_TABLE = { - 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, - 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, - 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, - 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, - 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, - 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, - 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, - 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, - 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, - 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, - 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, - 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, - 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, - 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, - 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, - 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, - 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, - 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, - 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, - 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, - 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, - 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, - 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, - 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, - 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, - 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, - 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, - 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, - 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, - 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, - 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, - 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040, - }; + private int[] initTable8() { + int[] table = new int[256]; + int crc; + for (int i = 0; i < 256; i++) { + crc = i; + for (int j = 0; j < 8; j++) { + boolean bit = (crc & 0x80) != 0; + crc <<= 1; + if (bit) { + crc ^= poly; + } + } + table[i] = crc & 0xFF; + } + return table; + } - private static final int[] CRC8_TABLE = { - 0x00, 0x31, 0x62, 0x53, 0xC4, 0xF5, 0xA6, 0x97, - 0xB9, 0x88, 0xDB, 0xEA, 0x7D, 0x4C, 0x1F, 0x2E, - 0x43, 0x72, 0x21, 0x10, 0x87, 0xB6, 0xE5, 0xD4, - 0xFA, 0xCB, 0x98, 0xA9, 0x3E, 0x0F, 0x5C, 0x6D, - 0x86, 0xB7, 0xE4, 0xD5, 0x42, 0x73, 0x20, 0x11, 0x3F, - 0x0E, 0x5D, 0x6C, 0xFB, 0xCA, 0x99, 0xA8, 0xC5, 0xF4, 0xA7, 0x96, - 0x01, 0x30, 0x63, 0x52, 0x7C, 0x4D, 0x1E, 0x2F, 0xB8, 0x89, 0xDA, - 0xEB, 0x3D, 0x0C, 0x5F, 0x6E, 0xF9, 0xC8, 0x9B, 0xAA, 0x84, 0xB5, - 0xE6, 0xD7, 0x40, 0x71, 0x22, 0x13, 0x7E, 0x4F, 0x1C, 0x2D, 0xBA, - 0x8B, 0xD8, 0xE9, 0xC7, 0xF6, 0xA5, 0x94, 0x03, 0x32, 0x61, 0x50, - 0xBB, 0x8A, 0xD9, 0xE8, 0x7F, 0x4E, 0x1D, 0x2C, 0x02, 0x33, 0x60, - 0x51, 0xC6, 0xF7, 0xA4, 0x95, 0xF8, 0xC9, 0x9A, 0xAB, 0x3C, 0x0D, - 0x5E, 0x6F, 0x41, 0x70, 0x23, 0x12, 0x85, 0xB4, 0xE7, 0xD6, 0x7A, - 0x4B, 0x18, 0x29, 0xBE, 0x8F, 0xDC, 0xED, 0xC3, 0xF2, 0xA1, 0x90, - 0x07, 0x36, 0x65, 0x54, 0x39, 0x08, 0x5B, 0x6A, 0xFD, 0xCC, 0x9F, - 0xAE, 0x80, 0xB1, 0xE2, 0xD3, 0x44, 0x75, 0x26, 0x17, 0xFC, 0xCD, - 0x9E, 0xAF, 0x38, 0x09, 0x5A, 0x6B, 0x45, 0x74, 0x27, 0x16, 0x81, - 0xB0, 0xE3, 0xD2, 0xBF, 0x8E, 0xDD, 0xEC, 0x7B, 0x4A, 0x19, 0x28, - 0x06, 0x37, 0x64, 0x55, 0xC2, 0xF3, 0xA0, 0x91, 0x47, 0x76, 0x25, - 0x14, 0x83, 0xB2, 0xE1, 0xD0, 0xFE, 0xCF, 0x9C, 0xAD, 0x3A, 0x0B, - 0x58, 0x69, 0x04, 0x35, 0x66, 0x57, 0xC0, 0xF1, 0xA2, 0x93, 0xBD, - 0x8C, 0xDF, 0xEE, 0x79, 0x48, 0x1B, 0x2A, 0xC1, 0xF0, 0xA3, 0x92, - 0x05, 0x34, 0x67, 0x56, 0x78, 0x49, 0x1A, 0x2B, 0xBC, 0x8D, 0xDE, - 0xEF, 0x82, 0xB3, 0xE0, 0xD1, 0x46, 0x77, 0x24, 0x15, 0x3B, 0x0A, - 0x59, 0x68, 0xFF, 0xCE, 0x9D, 0xAC }; + private int[] initTable16() { + int[] table = new int[256]; + int crc; + for (int i = 0; i < 256; i++) { + crc = i << 8; + for (int j = 0; j < 8; j++) { + boolean bit = (crc & 0x8000) != 0; + crc <<= 1; + if (bit) { + crc ^= poly; + } + } + table[i] = crc & 0xFFFF; + } + return table; + } - // More info: http://reveng.sourceforge.net/crc-catalogue/16.htm - public static final String CRC16_IBM = "IBM"; - public static final String CRC16_MODBUS = "MODBUS"; - public static final String CRC16_X25 = "X-25"; - public static final String CRC16_CCITT_FALSE = "CCITT-FALSE"; - public static final String CRC16_KERMIT = "KERMIT"; - public static final String CRC16_XMODEM = "XMODEM"; - public static final String CRC16_AUG_CCITT = "AUG-CCITT"; - public static final String CRC16_GENIBUS = "GENIBUS"; - public static final String CRC16_MCRF4XX = "MCRF4XX"; + } - private static int crc16Unreflected(ByteBuffer buf, int crcIn, int[] table) { - int crc16 = crcIn; - while (buf.hasRemaining()) { - crc16 = table[((crc16 >> 8) ^ buf.get()) & 0xff] ^ (crc16 << 8); + private static int reverse(int value, int bits) { + int result = 0; + for (int i = 0; i < bits; i++) { + result = (result << 1) | (value & 1); + value >>= 1; } - return crc16 & 0xFFFF; + return result; } - private static int crc16Reflected(ByteBuffer buf, int crcIn, int[] table) { - int crc16 = crcIn; + public static int crc8(Algorithm algorithm, ByteBuffer buf) { + int crc = algorithm.init; while (buf.hasRemaining()) { - crc16 = table[(crc16 ^ buf.get()) & 0xff] ^ (crc16 >> 8); + int b = buf.get() & 0xFF; + if (algorithm.refIn) { + b = reverse(b, 8); + } + crc = algorithm.table[(crc & 0xFF) ^ b]; } - return crc16 & 0xFFFF; - } - - public static int crc16(String type, ByteBuffer buf) { - switch (type) { - case CRC16_IBM: - return crc16Reflected(buf, 0, CRC16_IBM_TABLE); - case CRC16_MODBUS: - return crc16Reflected(buf, 0xFFFF, CRC16_IBM_TABLE); - case CRC16_X25: - return crc16Reflected(buf, 0xFFFF, CRC16_CCITT_TABLE_REVERSE) ^ 0xFFFF; - case CRC16_CCITT_FALSE: - return crc16Unreflected(buf, 0xFFFF, CRC16_CCITT_TABLE); - case CRC16_KERMIT: - return crc16Reflected(buf, 0, CRC16_CCITT_TABLE_REVERSE); - case CRC16_XMODEM: - return crc16Unreflected(buf, 0, CRC16_CCITT_TABLE); - case CRC16_AUG_CCITT: - return crc16Unreflected(buf, 0x1d0f, CRC16_CCITT_TABLE); - case CRC16_GENIBUS: - return crc16Unreflected(buf, 0xFFFF, CRC16_CCITT_TABLE) ^ 0xFFFF; - case CRC16_MCRF4XX: - return crc16Reflected(buf, 0xFFFF, CRC16_CCITT_TABLE_REVERSE); - default: - throw new UnsupportedOperationException(type); + if (algorithm.refOut) { + crc = reverse(crc, 8); } + return (crc ^ algorithm.xorOut) & 0xFF; } - public static int crc8(ByteBuffer buf) { - int crc = 0xFF; + public static int crc16(Algorithm algorithm, ByteBuffer buf) { + int crc = algorithm.init; while (buf.hasRemaining()) { - crc = CRC8_TABLE[(crc ^ buf.get()) & 0xFF]; + int b = buf.get() & 0xFF; + if (algorithm.refIn) { + b = reverse(b, 8); + } + crc = (crc << 8) ^ algorithm.table[((crc >> 8) & 0xFF) ^ b]; + } + if (algorithm.refOut) { + crc = reverse(crc, 16); } - return crc & 0xFF; + return (crc ^ algorithm.xorOut) & 0xFFFF; } + public static final Algorithm CRC8_EGTS = new Algorithm(8, 0x31, 0xFF, false, false, 0x00); + public static final Algorithm CRC8_ROHC = new Algorithm(8, 0x07, 0xFF, true, true, 0x00); + + public static final Algorithm CRC16_IBM = new Algorithm(16, 0x8005, 0x0000, true, true, 0x0000); + public static final Algorithm CRC16_X25 = new Algorithm(16, 0x1021, 0xFFFF, true, true, 0xFFFF); + public static final Algorithm CRC16_MODBUS = new Algorithm(16, 0x8005, 0xFFFF, true, true, 0x0000); + public static final Algorithm CRC16_CCITT_FALSE = new Algorithm(16, 0x1021, 0xFFFF, false, false, 0x0000); + public static final Algorithm CRC16_KERMIT = new Algorithm(16, 0x1021, 0x0000, true, true, 0x0000); + public static final Algorithm CRC16_XMODEM = new Algorithm(16, 0x1021, 0x0000, false, false, 0x0000); + public static int crc32(ByteBuffer buf) { CRC32 checksum = new CRC32(); while (buf.hasRemaining()) { diff --git a/src/org/traccar/protocol/EgtsProtocolDecoder.java b/src/org/traccar/protocol/EgtsProtocolDecoder.java index 85376b1a5..fe82a51ed 100644 --- a/src/org/traccar/protocol/EgtsProtocolDecoder.java +++ b/src/org/traccar/protocol/EgtsProtocolDecoder.java @@ -97,7 +97,7 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder { response.writeShort(record.readableBytes()); response.writeShort(packetId++); response.writeByte(packetType); - response.writeByte(Checksum.crc8(response.toByteBuffer())); + response.writeByte(Checksum.crc8(Checksum.CRC8_EGTS, response.toByteBuffer())); response.writeBytes(record); response.writeShort(recordChecksum); diff --git a/test/org/traccar/helper/ChecksumTest.java b/test/org/traccar/helper/ChecksumTest.java index a7c66a2a2..3bd51448d 100644 --- a/test/org/traccar/helper/ChecksumTest.java +++ b/test/org/traccar/helper/ChecksumTest.java @@ -10,19 +10,26 @@ import static org.junit.Assert.assertEquals; public class ChecksumTest { + @Test + public void testCrc8() { + ChannelBuffer buf = ChannelBuffers.copiedBuffer("123456789", StandardCharsets.US_ASCII); + + assertEquals(0xF7, Checksum.crc8(Checksum.CRC8_EGTS, buf.toByteBuffer())); + assertEquals(0xD0, Checksum.crc8(Checksum.CRC8_ROHC, buf.toByteBuffer())); + } + @Test public void testCrc16() { ChannelBuffer buf = ChannelBuffers.copiedBuffer("123456789", StandardCharsets.US_ASCII); + assertEquals(0xBB3D, Checksum.crc16(Checksum.CRC16_IBM, buf.toByteBuffer())); + assertEquals(0x4B37, Checksum.crc16(Checksum.CRC16_MODBUS, buf.toByteBuffer())); assertEquals(0x906e, Checksum.crc16(Checksum.CRC16_X25, buf.toByteBuffer())); assertEquals(0x29b1, Checksum.crc16(Checksum.CRC16_CCITT_FALSE, buf.toByteBuffer())); assertEquals(0x2189, Checksum.crc16(Checksum.CRC16_KERMIT, buf.toByteBuffer())); assertEquals(0x31c3, Checksum.crc16(Checksum.CRC16_XMODEM, buf.toByteBuffer())); - assertEquals(0xe5cc, Checksum.crc16(Checksum.CRC16_AUG_CCITT, buf.toByteBuffer())); - assertEquals(0xd64e, Checksum.crc16(Checksum.CRC16_GENIBUS, buf.toByteBuffer())); - assertEquals(0x6f91, Checksum.crc16(Checksum.CRC16_MCRF4XX, buf.toByteBuffer())); } - + @Test public void testLuhn() { assertEquals(7, Checksum.luhn(12345678901234L)); -- cgit v1.2.3