From 2204c9830058fe33a4bf426636468a9ec0749a83 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 27 Sep 2021 12:27:53 -0700 Subject: Add custom frame decoder --- .../traccar/protocol/NavtelecomFrameDecoder.java | 75 ++++++++++++++++++++++ .../org/traccar/protocol/NavtelecomProtocol.java | 5 +- .../protocol/NavtelecomProtocolDecoder.java | 6 +- .../protocol/NavtelecomFrameDecoderTest.java | 44 +++++++++++++ 4 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/traccar/protocol/NavtelecomFrameDecoder.java create mode 100644 src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java (limited to 'src') diff --git a/src/main/java/org/traccar/protocol/NavtelecomFrameDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomFrameDecoder.java new file mode 100644 index 000000000..0fb82528b --- /dev/null +++ b/src/main/java/org/traccar/protocol/NavtelecomFrameDecoder.java @@ -0,0 +1,75 @@ +/* + * Copyright 2021 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; +import org.traccar.BasePipelineFactory; + +import java.nio.charset.StandardCharsets; +import java.util.BitSet; + +public class NavtelecomFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.getByte(buf.readerIndex()) == '@') { + + int length = buf.getUnsignedShortLE(12) + 12 + 2 + 2; + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + } else { + + NavtelecomProtocolDecoder protocolDecoder = + BasePipelineFactory.getHandler(ctx.pipeline(), NavtelecomProtocolDecoder.class); + if (protocolDecoder == null) { + throw new RuntimeException("Decoder not found"); + } + + String type = buf.getCharSequence(buf.readerIndex(), 2, StandardCharsets.US_ASCII).toString(); + BitSet bits = protocolDecoder.getBits(); + + if (type.equals("~A")) { + int count = buf.getUnsignedByte(buf.readerIndex() + 2); + int length = 2 + 1 + 1; + + for (int i = 0; i < count; i++) { + for (int j = 0; j < bits.length(); j++) { + if (bits.get(j)) { + length += NavtelecomProtocolDecoder.getItemLength(j + 1); + } + } + } + + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + } else { + throw new UnsupportedOperationException("Unsupported message type: " + type); + } + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocol.java b/src/main/java/org/traccar/protocol/NavtelecomProtocol.java index 24bfbf895..29ce8c41e 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocol.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocol.java @@ -15,20 +15,17 @@ */ package org.traccar.protocol; -import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; -import java.nio.ByteOrder; - public class NavtelecomProtocol extends BaseProtocol { public NavtelecomProtocol() { addServer(new TrackerServer(false, getName()) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 65535, 12, 2, 2, 0, true)); + pipeline.addLast(new NavtelecomFrameDecoder()); pipeline.addLast(new NavtelecomProtocolDecoder(NavtelecomProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java index c469025c2..bdcc12c4c 100644 --- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java @@ -95,7 +95,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { private BitSet bits; - private static int getItemLength(int id) { + public static int getItemLength(int id) { Integer length = ITEM_LENGTH_MAP.get(id); if (length == null) { throw new IllegalArgumentException(String.format("Unknown item: %d", id)); @@ -103,6 +103,10 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder { return length; } + public BitSet getBits() { + return bits; + } + private void sendResponse( Channel channel, SocketAddress remoteAddress, int receiver, int sender, ByteBuf content) { if (channel != null) { diff --git a/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java b/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java new file mode 100644 index 000000000..07b19651b --- /dev/null +++ b/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java @@ -0,0 +1,44 @@ +package org.traccar.protocol; + +import org.junit.Ignore; +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class NavtelecomFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = new NavtelecomFrameDecoder(); + + verifyFrame( + binary("404e5443010000000000000013004e452a3e533a383636373935303331343130363839"), + decoder.decode(null, null, binary("404e5443010000000000000013004e452a3e533a383636373935303331343130363839"))); + + verifyFrame( + binary("404e544301000000000000002a005e6c2a3e464c4558b01e1efffffe300a08080ffffe08000000580028002bc0000000000000b4000000000000"), + decoder.decode(null, null, binary("404e544301000000000000002a005e6c2a3e464c4558b01e1efffffe300a08080ffffe08000000580028002bc0000000000000b4000000000000"))); + + } + + @Ignore + @Test + public void testDecodeFull() throws Exception { + + var decoder = new NavtelecomFrameDecoder(); + + verifyFrame( + binary("404e5443010000000000000013004e452a3e533a383636373935303331343130363839"), + decoder.decode(null, null, binary("404e5443010000000000000013004e452a3e533a383636373935303331343130363839"))); + + verifyFrame( + binary("404e544301000000000000002a005e6c2a3e464c4558b01e1efffffe300a08080ffffe08000000580028002bc0000000000000b4000000000000"), + decoder.decode(null, null, binary("404e544301000000000000002a005e6c2a3e464c4558b01e1efffffe300a08080ffffe08000000580028002bc0000000000000b4000000000000"))); + + verifyFrame( + binary("7e4104022106000517c4ae2f6180a9000e2fc4ae2f61471dff0171b35801d2050000a9870e412801d9d096466a37061000009474270080ff7f00000000ffff8000000000ffffffffffffffffffffffffffff7f00000000ffffff0308000000000000090cf70900000826fa000200b3ad2b00000826fa000200aad75200000826fa000200aa9cae2f6158020000000000000000000a14000000000000000000000000000000000000000026000000032106000b17dbae2f6180a9000e33daae2f61a11dff01edb15801d00500009c50e83f2f01ecd09646793706100000ab74270080ff7f00000000ffff8000000000ffffffffffffffffffffffffffff7f00000000ffffff0408000000000000090bf70900000826fa000200af8bc70000256cfa000200ab3e7c0000256cfa000200aad7ae2f61fd080000000000000000000a140100000000000000000000000000000000000000260000000421060054a0e7ae2f6180a9000e33e6ae2f61ba1dff01beb15801d305000038b977402201f0d09646163706100000b674270080ff7f00000000ffff8000000000ffffffffffffffffffffffffffff7f00000000ffffff0309000000000000080bf70900000826fa000200af8bc70000256cfa000200ab3e7c0000256cfa000200aad7ae2f6173040000000000000000000a14080000000000000000000000000000000000000026000000052106000517efae2f6180a9000f33efae2f61c21dff0166b15801df05000017f145404d00f5d09646693706100000bf74270080ff7f00000000ffff8000000000ffffffffffffffffffffffffffff7f00000000ffffff0408000000000000090cf70900000826fa000200af8bc70000256cfa000200ab3e7c0000256cfa000200aad7ae2f615b030000000000000000000a14020000000000000000000000000000000000000026000000a9"), + decoder.decode(null, null, binary("7e4104022106000517c4ae2f6180a9000e2fc4ae2f61471dff0171b35801d2050000a9870e412801d9d096466a37061000009474270080ff7f00000000ffff8000000000ffffffffffffffffffffffffffff7f00000000ffffff0308000000000000090cf70900000826fa000200b3ad2b00000826fa000200aad75200000826fa000200aa9cae2f6158020000000000000000000a14000000000000000000000000000000000000000026000000032106000b17dbae2f6180a9000e33daae2f61a11dff01edb15801d00500009c50e83f2f01ecd09646793706100000ab74270080ff7f00000000ffff8000000000ffffffffffffffffffffffffffff7f00000000ffffff0408000000000000090bf70900000826fa000200af8bc70000256cfa000200ab3e7c0000256cfa000200aad7ae2f61fd080000000000000000000a140100000000000000000000000000000000000000260000000421060054a0e7ae2f6180a9000e33e6ae2f61ba1dff01beb15801d305000038b977402201f0d09646163706100000b674270080ff7f00000000ffff8000000000ffffffffffffffffffffffffffff7f00000000ffffff0309000000000000080bf70900000826fa000200af8bc70000256cfa000200ab3e7c0000256cfa000200aad7ae2f6173040000000000000000000a14080000000000000000000000000000000000000026000000052106000517efae2f6180a9000f33efae2f61c21dff0166b15801df05000017f145404d00f5d09646693706100000bf74270080ff7f00000000ffff8000000000ffffffffffffffffffffffffffff7f00000000ffffff0408000000000000090cf70900000826fa000200af8bc70000256cfa000200ab3e7c0000256cfa000200aad7ae2f615b030000000000000000000a14020000000000000000000000000000000000000026000000a9"))); + + } + +} -- cgit v1.2.3