From e99f61a3d9a2a7708aaabc047cb73adb0ceb0cac Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 31 Aug 2019 12:18:14 -0700 Subject: Implement Race Dynamics protocol --- setup/default.xml | 1 + .../org/traccar/protocol/RaceDynamicsProtocol.java | 39 ++++++ .../protocol/RaceDynamicsProtocolDecoder.java | 141 +++++++++++++++++++++ .../protocol/RaceDynamicsProtocolDecoderTest.java | 21 +++ 4 files changed, 202 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java create mode 100644 src/main/java/org/traccar/protocol/RaceDynamicsProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java diff --git a/setup/default.xml b/setup/default.xml index c5046ae83..7a321ed3c 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -271,5 +271,6 @@ 5192 5193 5194 + 5195 diff --git a/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java b/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java new file mode 100644 index 000000000..749893d4d --- /dev/null +++ b/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 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. + * 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.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class RaceDynamicsProtocol extends BaseProtocol { + + public RaceDynamicsProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new RaceDynamicsProtocolDecoder(RaceDynamicsProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/RaceDynamicsProtocolDecoder.java b/src/main/java/org/traccar/protocol/RaceDynamicsProtocolDecoder.java new file mode 100644 index 000000000..33b08115d --- /dev/null +++ b/src/main/java/org/traccar/protocol/RaceDynamicsProtocolDecoder.java @@ -0,0 +1,141 @@ +/* + * Copyright 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. + * 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.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; + +public class RaceDynamicsProtocolDecoder extends BaseProtocolDecoder { + + public RaceDynamicsProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_LOGIN = 12; + public static final int MSG_LOCATION = 15; + + private static final Pattern PATTERN_LOGIN = new PatternBuilder() + .text("$GPRMC,") + .number("d+,") // type + .number("d{6},") // date + .number("d{6},") // time + .number("(d{15}),") + .compile(); + + private static final Pattern PATTERN_LOCATION = new PatternBuilder() + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+),") // speed + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(-?d+),") // altitude + .number("(d+),") // satellites + .number("([01]),") // ignition + .number("(d+),") // index + .text("%,") + .number("([^,]+),") // ibutton + .number("d+,") // acceleration + .number("d+,") // deceleration + .number("[01],") // cruise control + .number("[01],") // seat belt + .number("[01],") // wrong ibutton + .number("(d+),") // power + .number("[01],") // power status + .number("(d+),") // battery + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + int type = Integer.parseInt(sentence.substring(7, 9)); + + if (type == MSG_LOGIN) { + + Parser parser = new Parser(PATTERN_LOGIN, sentence); + if (parser.matches()) { + getDeviceSession(channel, remoteAddress, parser.next()); + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(sentence + "\r\n", remoteAddress)); + } + } + + } else if (type == MSG_LOCATION) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + for (String data : sentence.substring(17, sentence.length() - 3).split(",#,#,")) { + Parser parser = new Parser(PATTERN_LOCATION, data); + if (parser.matches()) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble()); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + position.setAltitude(parser.nextInt()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_IGNITION, parser.nextInt() == 1); + position.set(Position.KEY_INDEX, parser.nextInt()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + position.set(Position.KEY_POWER, parser.nextInt() * 0.01); + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.01); + + positions.add(position); + + } + } + + return positions; + + } + + return null; + } + +} diff --git a/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java new file mode 100644 index 000000000..318cbdb51 --- /dev/null +++ b/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class RaceDynamicsProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + RaceDynamicsProtocolDecoder decoder = new RaceDynamicsProtocolDecoder(null); + + verifyNull(decoder, text( + "$GPRMC,12,260819,100708,862549040661129,")); + + verifyPositions(decoder, text( + "$GPRMC,15,04,H,#,100632,A,1255.5106,N,07738.2954,E,001,260819,0887,06,1,00011,%,0000000000000000,000,000,0,0,1,0713,0,416,0,255,000,0,000,3258,000,000,00,0000,000,00000,0,F3VF01,%,#,#,100633,A,1255.5107,N,07738.2955,E,001,260819,0887,06,1,00012,%,0000000000000000,000,000,0,0,1,0713,0,416,0,255,000,0,000,3453,000,000,00,0000,000,00000,0,F3VF01,%,#,#,100634,A,1255.5106,N,07738.2964,E,001,260819,0887,06,1,00013,%,0000000000000000,000,000,0,0,1,0713,0,392,0,255,000,0,000,3651,000,000,00,0000,000")); + + } + +} -- cgit v1.2.3