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 --- test/org/traccar/ProtocolTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/org') diff --git a/test/org/traccar/ProtocolTest.java b/test/org/traccar/ProtocolTest.java index e67b53aa8..75a98000b 100644 --- a/test/org/traccar/ProtocolTest.java +++ b/test/org/traccar/ProtocolTest.java @@ -5,11 +5,11 @@ import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpVersion; +import org.traccar.helper.DataConverter; import org.traccar.model.CellTower; import org.traccar.model.Command; import org.traccar.model.Position; -import javax.xml.bind.DatatypeConverter; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; import java.text.DateFormat; @@ -56,7 +56,7 @@ public class ProtocolTest extends BaseTest { protected ChannelBuffer binary(ByteOrder endianness, String... data) { return ChannelBuffers.wrappedBuffer( - endianness, DatatypeConverter.parseHexBinary(concatenateStrings(data))); + endianness, DataConverter.parseHex(concatenateStrings(data))); } protected String text(String... data) { -- cgit v1.2.3 From 8874b4bf69f38ef94d70bef2a8e4d52e0845fa77 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 12 Mar 2018 00:51:46 +1300 Subject: Support STEPP 3 FALCOM messages --- src/org/traccar/protocol/T55ProtocolDecoder.java | 8 +++++--- test/org/traccar/protocol/T55ProtocolDecoderTest.java | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'test/org') diff --git a/src/org/traccar/protocol/T55ProtocolDecoder.java b/src/org/traccar/protocol/T55ProtocolDecoder.java index dbc467993..be3cb5f67 100644 --- a/src/org/traccar/protocol/T55ProtocolDecoder.java +++ b/src/org/traccar/protocol/T55ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2017 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. @@ -250,9 +250,11 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder { } else if (sentence.startsWith("$PCPTI")) { getDeviceSession(channel, remoteAddress, sentence.substring(7, sentence.indexOf(",", 7))); } else if (sentence.startsWith("IMEI")) { - getDeviceSession(channel, remoteAddress, sentence.substring(5, sentence.length())); + getDeviceSession(channel, remoteAddress, sentence.substring(5)); + } else if (sentence.startsWith("$IMEI")) { + getDeviceSession(channel, remoteAddress, sentence.substring(6)); } else if (sentence.startsWith("$GPFID")) { - deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(7, sentence.length())); + deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(7)); if (deviceSession != null && position != null) { Position position = this.position; position.setDeviceId(deviceSession.getDeviceId()); diff --git a/test/org/traccar/protocol/T55ProtocolDecoderTest.java b/test/org/traccar/protocol/T55ProtocolDecoderTest.java index 7f60a1807..ec699f111 100644 --- a/test/org/traccar/protocol/T55ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/T55ProtocolDecoderTest.java @@ -10,12 +10,18 @@ public class T55ProtocolDecoderTest extends ProtocolTest { T55ProtocolDecoder decoder = new T55ProtocolDecoder(new T55Protocol()); + verifyNull(decoder, text( + "$IMEI=355797031609284")); + verifyNull(decoder, text( "086415031C20")); verifyNull(decoder, text( "358244017671308")); + verifyPosition(decoder, text( + "$GPRMC,192350.000,V,0000.0000,N,00000.0000,E,,,110318,,*12")); + verifyPosition(decoder, text( "$GPRMC,073446.000,A,1255.5125,N,07738.2948,E,0.00,0.53,080316,D*71,11,865733027593268,1,090,086,123,456,789,987,12345")); -- cgit v1.2.3 From d5c79363d91f6ae8594fe2cdde447c7efefaa798 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 12 Mar 2018 02:58:34 +1300 Subject: Support Lantrix T1700 TAIP protocol --- src/org/traccar/protocol/TaipProtocolDecoder.java | 72 ++++++++++++++-------- .../traccar/protocol/TaipProtocolDecoderTest.java | 3 + 2 files changed, 48 insertions(+), 27 deletions(-) (limited to 'test/org') diff --git a/src/org/traccar/protocol/TaipProtocolDecoder.java b/src/org/traccar/protocol/TaipProtocolDecoder.java index 9555d19e9..a7aa9dd96 100644 --- a/src/org/traccar/protocol/TaipProtocolDecoder.java +++ b/src/org/traccar/protocol/TaipProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -62,16 +62,23 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { .number("(ddd)") // speed .number("(ddd)") // course .groupBegin() + .number("([023])") // fix mode + .number("xx") // data age + .number("(xx)") // input + .number("(dd)") // event + .number("(dd)") // hdop + .or() + .groupBegin() .number("(xx)") // input .number("(xx)") // satellites .number("(ddd)") // battery .number("(x{8})") // odometer .number("[01]") // gps power .groupBegin() - .number("[23]") // fix mode + .number("([023])") // fix mode .number("(dd)") // pdop .number("dd") // satellites - .number("xxxx") // seconds from last + .number("xxxx") // data age .number("[01]") // modem power .number("[0-5]") // gsm status .number("(dd)") // rssi @@ -81,6 +88,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { .number("xx") // seconds from last .groupEnd("?") .groupEnd("?") + .groupEnd() .any() .compile(); @@ -116,6 +124,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); + Boolean valid = null; Integer event = null; if (parser.hasNext(3)) { @@ -129,27 +138,6 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { event = parser.nextInt(); } - if (event != null) { - switch (event) { - case 22: - position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); - break; - case 23: - position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - break; - case 24: - position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); - break; - case 26: - case 28: - position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); - break; - default: - position.set(Position.KEY_EVENT, event); - break; - } - } - if (parser.hasNext(6)) { position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); } @@ -166,6 +154,15 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble(0))); position.setCourse(parser.nextDouble(0)); + if (parser.hasNext(4)) { + valid = parser.nextInt() > 0; + int input = parser.nextHexInt(); + position.set(Position.KEY_IGNITION, BitUtil.check(input, 7)); + position.set(Position.KEY_INPUT, input); + event = parser.nextInt(); + position.set(Position.KEY_HDOP, parser.nextInt()); + } + if (parser.hasNext(4)) { position.set(Position.KEY_INPUT, parser.nextHexInt(0)); position.set(Position.KEY_SATELLITES, parser.nextHexInt(0)); @@ -174,13 +171,35 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { } if (parser.hasNext(4)) { + valid = parser.nextInt() > 0; position.set(Position.KEY_PDOP, parser.nextInt()); position.set(Position.KEY_RSSI, parser.nextInt()); position.set(Position.PREFIX_TEMP + 1, parser.nextInt() * 0.01); position.set(Position.PREFIX_TEMP + 2, parser.nextInt() * 0.01); } - position.setValid(true); + position.setValid(valid != null ? valid : true); + + if (event != null) { + position.set(Position.KEY_EVENT, event); + switch (event) { + case 22: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 23: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 24: + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); + break; + case 26: + case 28: + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + break; + default: + break; + } + } String[] attributes = null; beginIndex = sentence.indexOf(';'); @@ -250,14 +269,13 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder { if (deviceSession != null) { if (channel != null) { if (messageIndex != null) { - String response = ">ACK;" + messageIndex + ";ID=" + uniqueId + ";*"; + String response = ">ACK;ID=" + uniqueId + ";" + messageIndex + ";*"; response += String.format("%02X", Checksum.xor(response)) + "<"; channel.write(response, remoteAddress); } else { channel.write(uniqueId, remoteAddress); } } - return position; } diff --git a/test/org/traccar/protocol/TaipProtocolDecoderTest.java b/test/org/traccar/protocol/TaipProtocolDecoderTest.java index a92e82498..264724ce9 100644 --- a/test/org/traccar/protocol/TaipProtocolDecoderTest.java +++ b/test/org/traccar/protocol/TaipProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class TaipProtocolDecoderTest extends ProtocolTest { TaipProtocolDecoder decoder = new TaipProtocolDecoder(new TaipProtocol()); + verifyPosition(decoder, text( + ">RGP211217112154-2748332-058946350000000FF7F2100;ID=AA01;#0002;*2D<")); + verifyPosition(decoder, text( ">RCV12270218010247-3471349-058400030002057F001200020A1D013010600001509+0000FF+0000FF;#1DE2;ID=7196;*03<")); -- cgit v1.2.3 From 4f3cd9dae285cfbd0ff541911381c08f50b59435 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 12 Mar 2018 04:56:12 +1300 Subject: Implement Castelcom fuel cut commands --- src/org/traccar/protocol/CastelProtocol.java | 8 ++- .../traccar/protocol/CastelProtocolDecoder.java | 1 + .../traccar/protocol/CastelProtocolEncoder.java | 73 ++++++++++++++++++++++ .../protocol/CastelProtocolEncoderTest.java | 22 +++++++ 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/org/traccar/protocol/CastelProtocolEncoder.java create mode 100644 test/org/traccar/protocol/CastelProtocolEncoderTest.java (limited to 'test/org') diff --git a/src/org/traccar/protocol/CastelProtocol.java b/src/org/traccar/protocol/CastelProtocol.java index db9df0674..d5ba5cd55 100644 --- a/src/org/traccar/protocol/CastelProtocol.java +++ b/src/org/traccar/protocol/CastelProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 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. @@ -21,6 +21,7 @@ import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; import org.traccar.BaseProtocol; import org.traccar.TrackerServer; +import org.traccar.model.Command; import java.nio.ByteOrder; import java.util.List; @@ -29,6 +30,9 @@ public class CastelProtocol extends BaseProtocol { public CastelProtocol() { super("castel"); + setSupportedDataCommands( + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME); } @Override @@ -37,6 +41,7 @@ public class CastelProtocol extends BaseProtocol { @Override protected void addSpecificHandlers(ChannelPipeline pipeline) { pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0)); + pipeline.addLast("objectEncoder", new CastelProtocolEncoder()); pipeline.addLast("objectDecoder", new CastelProtocolDecoder(CastelProtocol.this)); } }; @@ -46,6 +51,7 @@ public class CastelProtocol extends BaseProtocol { server = new TrackerServer(new ConnectionlessBootstrap(), getName()) { @Override protected void addSpecificHandlers(ChannelPipeline pipeline) { + pipeline.addLast("objectEncoder", new CastelProtocolEncoder()); pipeline.addLast("objectDecoder", new CastelProtocolDecoder(CastelProtocol.this)); } }; diff --git a/src/org/traccar/protocol/CastelProtocolDecoder.java b/src/org/traccar/protocol/CastelProtocolDecoder.java index ebd3d202c..44a5e213c 100644 --- a/src/org/traccar/protocol/CastelProtocolDecoder.java +++ b/src/org/traccar/protocol/CastelProtocolDecoder.java @@ -96,6 +96,7 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder { public static final short MSG_CC_LOGIN = 0x4001; public static final short MSG_CC_LOGIN_RESPONSE = (short) 0x8001; public static final short MSG_CC_HEARTBEAT = 0x4206; + public static final short MSG_CC_PETROL_CONTROL = 0x4583; public static final short MSG_CC_HEARTBEAT_RESPONSE = (short) 0x8206; private Position readPosition(DeviceSession deviceSession, ChannelBuffer buf) { diff --git a/src/org/traccar/protocol/CastelProtocolEncoder.java b/src/org/traccar/protocol/CastelProtocolEncoder.java new file mode 100644 index 000000000..d69fc62cf --- /dev/null +++ b/src/org/traccar/protocol/CastelProtocolEncoder.java @@ -0,0 +1,73 @@ +/* + * 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.protocol; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.traccar.BaseProtocolEncoder; +import org.traccar.Context; +import org.traccar.helper.Checksum; +import org.traccar.helper.Log; +import org.traccar.model.Command; + +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; + +public class CastelProtocolEncoder extends BaseProtocolEncoder { + + private ChannelBuffer encodeContent(long deviceId, int type, ChannelBuffer content) { + ChannelBuffer buf = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0); + String uniqueId = Context.getIdentityManager().getById(deviceId).getUniqueId(); + + buf.writeByte('@'); + buf.writeByte('@'); + + buf.writeShort(2 + 2 + 1 + 20 + content.readableBytes()); // length + + buf.writeByte(4); // protocol version + + buf.writeBytes(uniqueId.getBytes(StandardCharsets.US_ASCII)); + buf.writeZero(20 - uniqueId.length()); + + buf.writeShort(type); + buf.writeBytes(content); + + buf.writeShort(Checksum.crc16(Checksum.CRC16_X25, buf.toByteBuffer())); + + buf.writeByte('\r'); + buf.writeByte('\n'); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + ChannelBuffer content = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0); + switch (command.getType()) { + case Command.TYPE_ENGINE_STOP: + content.writeByte(1); + return encodeContent(command.getDeviceId(), CastelProtocolDecoder.MSG_CC_PETROL_CONTROL, content); + case Command.TYPE_ENGINE_RESUME: + content.writeByte(0); + return encodeContent(command.getDeviceId(), CastelProtocolDecoder.MSG_CC_PETROL_CONTROL, content); + default: + Log.warning(new UnsupportedOperationException(command.getType())); + break; + } + return null; + } + +} diff --git a/test/org/traccar/protocol/CastelProtocolEncoderTest.java b/test/org/traccar/protocol/CastelProtocolEncoderTest.java new file mode 100644 index 000000000..6e519363f --- /dev/null +++ b/test/org/traccar/protocol/CastelProtocolEncoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class CastelProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + CastelProtocolEncoder encoder = new CastelProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ENGINE_STOP); + + verifyCommand(encoder, command, binary("40401a00043132333435363738393031323334350000000000834501c7280d0a")); + + } + +} -- 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 'test/org') 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 b2ab0b471591494523b12e5f1810a481b2cd1a65 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 12 Mar 2018 06:44:27 +1300 Subject: Cautela NMEA conversion protocol --- setup/default.xml | 1 + src/org/traccar/protocol/CautelaProtocol.java | 47 +++++++++++++ .../traccar/protocol/CautelaProtocolDecoder.java | 77 ++++++++++++++++++++++ .../protocol/CautelaProtocolDecoderTest.java | 18 +++++ 4 files changed, 143 insertions(+) create mode 100644 src/org/traccar/protocol/CautelaProtocol.java create mode 100644 src/org/traccar/protocol/CautelaProtocolDecoder.java create mode 100644 test/org/traccar/protocol/CautelaProtocolDecoderTest.java (limited to 'test/org') diff --git a/setup/default.xml b/setup/default.xml index 6be2c08e3..81a3cd128 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -228,5 +228,6 @@ 5157 5158 5159 + 5160 diff --git a/src/org/traccar/protocol/CautelaProtocol.java b/src/org/traccar/protocol/CautelaProtocol.java new file mode 100644 index 000000000..89ab7a1d0 --- /dev/null +++ b/src/org/traccar/protocol/CautelaProtocol.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.protocol; + +import org.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.handler.codec.frame.LineBasedFrameDecoder; +import org.jboss.netty.handler.codec.string.StringDecoder; +import org.jboss.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.TrackerServer; + +import java.util.List; + +public class CautelaProtocol extends BaseProtocol { + + public CautelaProtocol() { + super("cautela"); + } + + @Override + public void initTrackerServers(List serverList) { + serverList.add(new TrackerServer(new ServerBootstrap(), getName()) { + @Override + protected void addSpecificHandlers(ChannelPipeline pipeline) { + pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024)); + pipeline.addLast("stringEncoder", new StringEncoder()); + pipeline.addLast("stringDecoder", new StringDecoder()); + pipeline.addLast("objectDecoder", new CautelaProtocolDecoder(CautelaProtocol.this)); + } + }); + } + +} diff --git a/src/org/traccar/protocol/CautelaProtocolDecoder.java b/src/org/traccar/protocol/CautelaProtocolDecoder.java new file mode 100644 index 000000000..94ba35c91 --- /dev/null +++ b/src/org/traccar/protocol/CautelaProtocolDecoder.java @@ -0,0 +1,77 @@ +/* + * 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.protocol; + +import org.jboss.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +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.regex.Pattern; + +public class CautelaProtocolDecoder extends BaseProtocolDecoder { + + public CautelaProtocolDecoder(CautelaProtocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(d+),") // type + .number("(d+),") // imei + .number("(dd),(dd),(dd),") // date (ddmmyy) + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .number("(dd)(dd),") // time (hhmm) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + String type = parser.next(); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder(); + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(true); + position.setLongitude(parser.nextDouble()); + position.setLatitude(parser.nextDouble()); + + dateBuilder.setHour(parser.nextInt()).setMinute(parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + return position; + } + +} diff --git a/test/org/traccar/protocol/CautelaProtocolDecoderTest.java b/test/org/traccar/protocol/CautelaProtocolDecoderTest.java new file mode 100644 index 000000000..4fd785c9f --- /dev/null +++ b/test/org/traccar/protocol/CautelaProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class CautelaProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + CautelaProtocolDecoder decoder = new CautelaProtocolDecoder(new CautelaProtocol()); + + verifyPosition(decoder, text( + "20,010907000000,14,02,18,16.816667,96.166667,1325,S,*2E")); + + } + +} -- cgit v1.2.3 From 612547f1b0cae5e0ba39359ed349799f2a87ca2f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 13 Mar 2018 01:00:09 +1300 Subject: Handle missing temperature (fix #3806) --- src/org/traccar/protocol/Gl200TextProtocolDecoder.java | 4 +++- test/org/traccar/protocol/Gl200TextProtocolDecoderTest.java | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'test/org') diff --git a/src/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/org/traccar/protocol/Gl200TextProtocolDecoder.java index 362fc38c7..ff300d429 100644 --- a/src/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -787,7 +787,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { for (int i = 1; i <= deviceCount; i++) { index += 1; // id index += 1; // type - position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(data[index++], 16) * 0.0625); + if (!data[index++].isEmpty()) { + position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(data[index - 1], 16) * 0.0625); + } } } diff --git a/test/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/test/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 9ec67273c..56a159768 100644 --- a/test/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { Gl200TextProtocolDecoder decoder = new Gl200TextProtocolDecoder(new Gl200Protocol()); + verifyPositions(decoder, buffer( + "+RESP:GTERI,310603,863286023345490,,00000002,,10,1,2,0.3,0,155.7,8.000000,52.000000,20171215213040,0262,0002,1450,9F13,00,1130.3,00539:27:19,,,110000,2,1,28FFD5239115034E,1,,20171215213041,27C7$")); + verifyPositions(decoder, buffer( "+RESP:GTERI,250C02,868789023691057,,00000019,,10,1,1,0.0,196,2258.0,-99.201807,19.559242,20180214002957,0334,0003,235B,7F8D,00,6786.7,,,,100,110000,1,0394,1,4,100.0,100.0,20180214003006,C72B$")); -- cgit v1.2.3 From 709b02703cfd974bc17127f3e4683b9d96249eb9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 13 Mar 2018 06:40:50 +1300 Subject: Support ATrack fuel sensor --- src/org/traccar/protocol/AtrackProtocolDecoder.java | 17 +++++++++++++++-- .../org/traccar/protocol/AtrackProtocolDecoderTest.java | 3 +++ 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'test/org') diff --git a/src/org/traccar/protocol/AtrackProtocolDecoder.java b/src/org/traccar/protocol/AtrackProtocolDecoder.java index 236b608d6..8138f0fcb 100644 --- a/src/org/traccar/protocol/AtrackProtocolDecoder.java +++ b/src/org/traccar/protocol/AtrackProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -36,6 +36,7 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.regex.Matcher; import java.util.regex.Pattern; public class AtrackProtocolDecoder extends BaseProtocolDecoder { @@ -43,6 +44,7 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { private static final int MIN_DATA_LENGTH = 40; private boolean longDate; + private boolean decimalFuel; private boolean custom; private String form; @@ -52,6 +54,7 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { super(protocol); longDate = Context.getConfig().getBoolean(getProtocolName() + ".longDate"); + decimalFuel = Context.getConfig().getBoolean(getProtocolName() + ".decimalFuel"); custom = Context.getConfig().getBoolean(getProtocolName() + ".custom"); form = Context.getConfig().getString(getProtocolName() + ".form"); @@ -330,7 +333,17 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_TEMP + 1, buf.readShort() * 0.1); position.set(Position.PREFIX_TEMP + 2, buf.readShort() * 0.1); - position.set("message", readString(buf)); + String message = readString(buf); + if (message != null && !message.isEmpty()) { + Pattern pattern = Pattern.compile("FULS:F=(\\p{XDigit}+) t=(\\p{XDigit}+) N=(\\p{XDigit}+)"); + Matcher matcher = pattern.matcher(message); + if (matcher.find()) { + int value = Integer.parseInt(matcher.group(3), decimalFuel ? 10 : 16); + position.set(Position.KEY_FUEL_LEVEL, value * 0.1); + } else { + position.set("message", message); + } + } if (custom) { String form = this.form; diff --git a/test/org/traccar/protocol/AtrackProtocolDecoderTest.java b/test/org/traccar/protocol/AtrackProtocolDecoderTest.java index b5271f511..bd606c320 100644 --- a/test/org/traccar/protocol/AtrackProtocolDecoderTest.java +++ b/test/org/traccar/protocol/AtrackProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class AtrackProtocolDecoderTest extends ProtocolTest { AtrackProtocolDecoder decoder = new AtrackProtocolDecoder(new AtrackProtocol()); + verifyPositions(decoder, binary( + "4050b5ed004a2523000310c83713f8c05a88b43e5a88b43f5a88b43f021e0ad5fffdc0a800f3020003059100080000000000000007d007d046554c533a463d3230393120743d3137204e3d3039303100")); + verifyAttributes(decoder, buffer( "$INFO=358683066267395,AX7,Rev.0.61 Build.1624,358683066267395,466924131626767,89886920041316267670,144,0,9,1,12,1,0\r\n")); -- cgit v1.2.3 From bb49f1e2c38e23860e87e1801edc456f30165d5f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 13 Mar 2018 16:46:42 +1300 Subject: DM G50 hello message response --- src/org/traccar/protocol/DmtProtocolDecoder.java | 15 ++++++++++----- test/org/traccar/protocol/DmtProtocolDecoderTest.java | 3 +++ 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'test/org') diff --git a/src/org/traccar/protocol/DmtProtocolDecoder.java b/src/org/traccar/protocol/DmtProtocolDecoder.java index 74db5a6f7..3739253f0 100644 --- a/src/org/traccar/protocol/DmtProtocolDecoder.java +++ b/src/org/traccar/protocol/DmtProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 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. @@ -70,8 +70,7 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder { buf.skipBytes(2); // header int type = buf.readUnsignedByte(); - - buf.readUnsignedShort(); // length + int length = buf.readUnsignedShort(); if (type == MSG_HELLO) { @@ -81,8 +80,14 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder { channel, remoteAddress, buf.readBytes(15).toString(StandardCharsets.US_ASCII)); ChannelBuffer response = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0); - response.writeInt((int) ((System.currentTimeMillis() - 1356998400000L) / 1000)); - response.writeInt(deviceSession != null ? 0 : 1); // flags + if (length == 51) { + response.writeByte(0); // reserved + response.writeInt(0); // reserved + } else { + response.writeInt((int) ((System.currentTimeMillis() - 1356998400000L) / 1000)); + response.writeInt(deviceSession != null ? 0 : 1); // flags + } + sendResponse(channel, MSG_HELLO_RESPONSE, response); } else if (type == MSG_COMMIT) { diff --git a/test/org/traccar/protocol/DmtProtocolDecoderTest.java b/test/org/traccar/protocol/DmtProtocolDecoderTest.java index 2575d77ed..a83dcafe2 100644 --- a/test/org/traccar/protocol/DmtProtocolDecoderTest.java +++ b/test/org/traccar/protocol/DmtProtocolDecoderTest.java @@ -12,6 +12,9 @@ public class DmtProtocolDecoderTest extends ProtocolTest { DmtProtocolDecoder decoder = new DmtProtocolDecoder(new DmtProtocol()); + verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, + "0255003300001b00003335333232393032373533393235310038393931353030303030303030313330343539340000000403041910780603")); + verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, "025500310038f90100333533333233303831363639373330003839363130313835303031383234383434363330002202010900000000")); -- cgit v1.2.3 From 4ae3297dde98d292cd0c87141440f94312459b65 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 14 Mar 2018 06:08:04 +1300 Subject: Include Teltonika RDIF if not zero --- src/org/traccar/protocol/TeltonikaProtocolDecoder.java | 7 +++++-- test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'test/org') diff --git a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java index 9e249247a..d2069e6c9 100644 --- a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 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. @@ -133,7 +133,10 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_TEMP + 3, readValue(buf, length, true) * 0.1); break; case 78: - position.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", readValue(buf, length, false))); + long driverUniqueId = readValue(buf, length, false); + if (driverUniqueId != 0) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", driverUniqueId)); + } break; case 80: position.set("workMode", readValue(buf, length, false)); diff --git a/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java b/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java index c4fae52ff..d62eef4a0 100644 --- a/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java +++ b/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java @@ -14,6 +14,9 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "000F313233343536373839303132333435")); + verifyPositions(decoder, false, binary( + "0000000000000035080100000161f37c50500020de5ba60ef11450000000000000000006040100b300b400ef000109002000014e0000000000000000010000be52")); + verifyPositions(decoder, false, binary( "000000000000008c08010000013feb55ff74000f0ea850209a690000940000120000001e09010002000300040016014703f0001504c8000c0900730a00460b00501300464306d7440000b5000bb60007422e9f180000cd0386ce000107c700000000f10000601a46000001344800000bb84900000bb84a00000bb84c00000000024e0000000000000000cf00000000000000000100003fca")); -- cgit v1.2.3 From 7c7002e3b001b9e4f8f9a00f9a14dff87b5c9862 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 14 Mar 2018 07:58:15 +1300 Subject: Support Watch blood pressure --- src/org/traccar/protocol/WatchProtocolDecoder.java | 14 +++++++++----- test/org/traccar/protocol/WatchProtocolDecoderTest.java | 3 +++ 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'test/org') diff --git a/src/org/traccar/protocol/WatchProtocolDecoder.java b/src/org/traccar/protocol/WatchProtocolDecoder.java index 12ec3bd3f..325f2efd9 100644 --- a/src/org/traccar/protocol/WatchProtocolDecoder.java +++ b/src/org/traccar/protocol/WatchProtocolDecoder.java @@ -238,7 +238,7 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder { sendResponse(channel, manufacturer, id, index, "TKQ"); - } else if (type.equals("PULSE") || type.equals("heart")) { + } else if (type.equals("PULSE") || type.equals("heart") || type.equals("bphrt")) { if (buf.readable()) { @@ -247,10 +247,14 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder { getLastLocation(position, new Date()); - position.setValid(false); - String pulse = buf.toString(StandardCharsets.US_ASCII); - position.set("pulse", pulse); - position.set(Position.KEY_RESULT, pulse); + String[] values = buf.toString(StandardCharsets.US_ASCII).split(","); + int valueIndex = 0; + + if (type.equals("bphrt")) { + position.set("pressureLow", values[valueIndex++]); + position.set("pressureHigh", values[valueIndex++]); + } + position.set("pulse", values[valueIndex]); return position; diff --git a/test/org/traccar/protocol/WatchProtocolDecoderTest.java b/test/org/traccar/protocol/WatchProtocolDecoderTest.java index 657cb0640..6ba04bf8e 100644 --- a/test/org/traccar/protocol/WatchProtocolDecoderTest.java +++ b/test/org/traccar/protocol/WatchProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class WatchProtocolDecoderTest extends ProtocolTest { WatchProtocolDecoder decoder = new WatchProtocolDecoder(new WatchProtocol()); + verifyAttributes(decoder, buffer( + "[3G*4700609403*0013*bphrt,120,79,73,,,,]")); + verifyPosition(decoder, buffer( "[3G*8308373902*0080*AL,230817,095346,A,47.083950,N,15.4821850,E,7.60,273.8,0.0,4,15,44,0,0,00200010,2,255,232,1,7605,42530,118,7605,58036,119,0,65.8]")); -- cgit v1.2.3 From 27a155908f6f460dde1a52c949cea7ee6625976a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 15 Mar 2018 16:05:10 +1300 Subject: Support DM G50 fixed 64 byte messages --- src/org/traccar/protocol/DmtProtocolDecoder.java | 262 +++++++++++++-------- .../traccar/protocol/DmtProtocolDecoderTest.java | 6 + 2 files changed, 175 insertions(+), 93 deletions(-) (limited to 'test/org') diff --git a/src/org/traccar/protocol/DmtProtocolDecoder.java b/src/org/traccar/protocol/DmtProtocolDecoder.java index 3739253f0..204d81820 100644 --- a/src/org/traccar/protocol/DmtProtocolDecoder.java +++ b/src/org/traccar/protocol/DmtProtocolDecoder.java @@ -21,6 +21,7 @@ import org.jboss.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.DeviceSession; import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; @@ -42,6 +43,7 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_DATA_RECORD = 0x04; public static final int MSG_COMMIT = 0x05; public static final int MSG_COMMIT_RESPONSE = 0x06; + public static final int MSG_DATA_RECORD_64 = 0x10; public static final int MSG_CANNED_REQUEST_1 = 0x14; public static final int MSG_CANNED_RESPONSE_1 = 0x15; @@ -61,6 +63,169 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder { } } + private List decodeFixed64(Channel channel, SocketAddress remoteAddress, ChannelBuffer buf) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + while (buf.readableBytes() >= 64) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readByte(); // type + + position.set(Position.KEY_INDEX, buf.readUnsignedInt()); + + long time = buf.readUnsignedInt(); + position.setTime(new DateBuilder() + .setYear((int) (2000 + (time & 0x3F))) + .setMonth((int) (time >> 6) & 0xF) + .setDay((int) (time >> 10) & 0x1F) + .setHour((int) (time >> 15) & 0x1F) + .setMinute((int) (time >> 20) & 0x3F) + .setSecond((int) (time >> 26) & 0x3F) + .getDate()); + + position.setLatitude(buf.readInt() * 0.0000001); + position.setLongitude(buf.readInt() * 0.0000001); + position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShort())); + position.setCourse(buf.readUnsignedByte() * 2); + position.setAltitude(buf.readShort()); + + buf.readUnsignedShort(); // position accuracy + buf.readUnsignedByte(); // speed accuracy + + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + + position.setValid(BitUtil.check(buf.readByte(), 0)); + + position.set(Position.KEY_INPUT, buf.readUnsignedInt()); + position.set(Position.KEY_OUTPUT, buf.readUnsignedShort()); + + for (int i = 1; i <= 5; i++) { + position.set(Position.PREFIX_ADC + i, buf.readShort()); + } + + position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); + + buf.readShort(); // accelerometer x + buf.readShort(); // accelerometer y + buf.readShort(); // accelerometer z + + buf.skipBytes(8); // device id + + position.set(Position.KEY_PDOP, buf.readUnsignedShort() * 0.01); + + buf.skipBytes(2); // reserved + + buf.readUnsignedShort(); // checksum + + positions.add(position); + } + + return positions; + } + + private List decodeStandard(Channel channel, SocketAddress remoteAddress, ChannelBuffer buf) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + while (buf.readable()) { + int recordEnd = buf.readerIndex() + buf.readUnsignedShort(); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_INDEX, buf.readUnsignedInt()); + + position.setDeviceTime(new Date(1356998400000L + buf.readUnsignedInt() * 1000)); // since 1 Jan 2013 + + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + + while (buf.readerIndex() < recordEnd) { + + int fieldId = buf.readUnsignedByte(); + int fieldLength = buf.readUnsignedByte(); + int fieldEnd = buf.readerIndex() + (fieldLength == 255 ? buf.readUnsignedShort() : fieldLength); + + if (fieldId == 0) { + + position.setFixTime(new Date(1356998400000L + buf.readUnsignedInt() * 1000)); + position.setLatitude(buf.readInt() * 0.0000001); + position.setLongitude(buf.readInt() * 0.0000001); + position.setAltitude(buf.readShort()); + position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShort())); + + buf.readUnsignedByte(); // speed accuracy + + position.setCourse(buf.readUnsignedByte() * 2); + + position.set(Position.KEY_PDOP, buf.readUnsignedByte() * 0.1); + + position.setAccuracy(buf.readUnsignedByte()); + position.setValid(buf.readUnsignedByte() != 0); + + } else if (fieldId == 2) { + + int input = buf.readInt(); + int output = buf.readUnsignedShort(); + int status = buf.readUnsignedShort(); + + position.set(Position.KEY_IGNITION, BitUtil.check(input, 0)); + + position.set(Position.KEY_INPUT, input); + position.set(Position.KEY_OUTPUT, output); + position.set(Position.KEY_STATUS, status); + + } else if (fieldId == 6) { + + while (buf.readerIndex() < fieldEnd) { + switch (buf.readUnsignedByte()) { + case 1: + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); + break; + case 2: + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); + break; + case 3: + position.set(Position.KEY_DEVICE_TEMP, buf.readShort() * 0.01); + break; + case 4: + position.set(Position.KEY_RSSI, buf.readUnsignedShort()); + break; + case 5: + position.set("solarPower", buf.readUnsignedShort() * 0.001); + break; + default: + break; + } + } + + } + + buf.readerIndex(fieldEnd); + + } + + if (position.getFixTime() == null) { + getLastLocation(position, position.getDeviceTime()); + } + + positions.add(position); + } + + return positions; + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -106,102 +271,13 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder { sendResponse(channel, MSG_CANNED_RESPONSE_2, null); - } else if (type == MSG_DATA_RECORD) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - while (buf.readable()) { - - int recordEnd = buf.readerIndex() + buf.readUnsignedShort(); - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_INDEX, buf.readUnsignedInt()); - - position.setDeviceTime(new Date(1356998400000L + buf.readUnsignedInt() * 1000)); // since 1 Jan 2013 - - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - - while (buf.readerIndex() < recordEnd) { + } else if (type == MSG_DATA_RECORD_64) { - int fieldId = buf.readUnsignedByte(); - int fieldLength = buf.readUnsignedByte(); - int fieldEnd = buf.readerIndex() + (fieldLength == 255 ? buf.readUnsignedShort() : fieldLength); + return decodeFixed64(channel, remoteAddress, buf); - if (fieldId == 0) { - - position.setFixTime(new Date(1356998400000L + buf.readUnsignedInt() * 1000)); - position.setLatitude(buf.readInt() * 0.0000001); - position.setLongitude(buf.readInt() * 0.0000001); - position.setAltitude(buf.readShort()); - position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShort())); - - buf.readUnsignedByte(); // speed accuracy - - position.setCourse(buf.readUnsignedByte() * 2); - - position.set(Position.KEY_PDOP, buf.readUnsignedByte() * 0.1); - - position.setAccuracy(buf.readUnsignedByte()); - position.setValid(buf.readUnsignedByte() != 0); - - } else if (fieldId == 2) { - - int input = buf.readInt(); - int output = buf.readUnsignedShort(); - int status = buf.readUnsignedShort(); - - position.set(Position.KEY_IGNITION, BitUtil.check(input, 0)); - - position.set(Position.KEY_INPUT, input); - position.set(Position.KEY_OUTPUT, output); - position.set(Position.KEY_STATUS, status); - - } else if (fieldId == 6) { - - while (buf.readerIndex() < fieldEnd) { - switch (buf.readUnsignedByte()) { - case 1: - position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); - break; - case 2: - position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); - break; - case 3: - position.set(Position.KEY_DEVICE_TEMP, buf.readShort() * 0.01); - break; - case 4: - position.set(Position.KEY_RSSI, buf.readUnsignedShort()); - break; - case 5: - position.set("solarPower", buf.readUnsignedShort() * 0.001); - break; - default: - break; - } - } - - } - - buf.readerIndex(fieldEnd); - - } - - if (position.getFixTime() == null) { - getLastLocation(position, position.getDeviceTime()); - } - - positions.add(position); - - } + } else if (type == MSG_DATA_RECORD) { - return positions; + return decodeStandard(channel, remoteAddress, buf); } diff --git a/test/org/traccar/protocol/DmtProtocolDecoderTest.java b/test/org/traccar/protocol/DmtProtocolDecoderTest.java index a83dcafe2..2e386c48e 100644 --- a/test/org/traccar/protocol/DmtProtocolDecoderTest.java +++ b/test/org/traccar/protocol/DmtProtocolDecoderTest.java @@ -15,6 +15,12 @@ public class DmtProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, "0255003300001b00003335333232393032373533393235310038393931353030303030303030313330343539340000000403041910780603")); + verifyPositions(decoder, false, binary(ByteOrder.LITTLE_ENDIAN, + "02551040000eaca40d00d2b8e562c51f9912f39a6bee00007e420091090903070100000000008b1065360000000000007fd401c4fcf2feffffffffffffffffee0000003f1b")); + + verifyPositions(decoder, false, binary(ByteOrder.LITTLE_ENDIAN, + "02551080000eada40d00d2b8e58ac51f9912f39a6bee00007e42007e090709070000000000009010fc330000000000007fc201a0fc04ffffffffffffffffffe5000000c5d00eaea40d00d2b8e58ac51f9912f39a6bee00007e42007e09070207000000000000851008340000000000007fc201a0fc04ff0000000000000000e5000000c96d")); + verifyNull(decoder, binary(ByteOrder.LITTLE_ENDIAN, "025500310038f90100333533333233303831363639373330003839363130313835303031383234383434363330002202010900000000")); -- cgit v1.2.3 From 411f12863460107187f1597b0bfd85627b1b413a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 16 Mar 2018 01:20:29 +1300 Subject: Update Gisgraphy test case --- test/org/traccar/geocoder/GeocoderTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/org') diff --git a/test/org/traccar/geocoder/GeocoderTest.java b/test/org/traccar/geocoder/GeocoderTest.java index 1ddc43ad2..8cf6ac524 100644 --- a/test/org/traccar/geocoder/GeocoderTest.java +++ b/test/org/traccar/geocoder/GeocoderTest.java @@ -83,9 +83,9 @@ public class GeocoderTest { public void onFailure(Throwable e) { } }); - assertEquals("Rue du Jardinet, Paris, FR", waitAddress()); + assertEquals("Rue du Jardinet, Paris, Île-de-France, FR", waitAddress()); - assertEquals("Rue du Jardinet, Paris, FR", geocoder.getAddress(48.8530000, 2.3400000, null)); + assertEquals("Rue du Jardinet, Paris, Île-de-France, FR", geocoder.getAddress(48.8530000, 2.3400000, null)); } public void testOpenCage() throws InterruptedException { -- cgit v1.2.3 From 34a5b8ceaff6617a8958ce04fb6c7f65d1d19979 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 16 Mar 2018 19:58:26 +1300 Subject: Fix Castel command encoding --- src/org/traccar/protocol/CastelProtocolEncoder.java | 4 ++-- test/org/traccar/protocol/CastelProtocolEncoderTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'test/org') diff --git a/src/org/traccar/protocol/CastelProtocolEncoder.java b/src/org/traccar/protocol/CastelProtocolEncoder.java index d69fc62cf..7ba33ca6d 100644 --- a/src/org/traccar/protocol/CastelProtocolEncoder.java +++ b/src/org/traccar/protocol/CastelProtocolEncoder.java @@ -28,7 +28,7 @@ import java.nio.charset.StandardCharsets; public class CastelProtocolEncoder extends BaseProtocolEncoder { - private ChannelBuffer encodeContent(long deviceId, int type, ChannelBuffer content) { + private ChannelBuffer encodeContent(long deviceId, short type, ChannelBuffer content) { ChannelBuffer buf = ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, 0); String uniqueId = Context.getIdentityManager().getById(deviceId).getUniqueId(); @@ -42,7 +42,7 @@ public class CastelProtocolEncoder extends BaseProtocolEncoder { buf.writeBytes(uniqueId.getBytes(StandardCharsets.US_ASCII)); buf.writeZero(20 - uniqueId.length()); - buf.writeShort(type); + buf.writeShort(ChannelBuffers.swapShort(type)); buf.writeBytes(content); buf.writeShort(Checksum.crc16(Checksum.CRC16_X25, buf.toByteBuffer())); diff --git a/test/org/traccar/protocol/CastelProtocolEncoderTest.java b/test/org/traccar/protocol/CastelProtocolEncoderTest.java index 6e519363f..fc0a92c86 100644 --- a/test/org/traccar/protocol/CastelProtocolEncoderTest.java +++ b/test/org/traccar/protocol/CastelProtocolEncoderTest.java @@ -15,7 +15,7 @@ public class CastelProtocolEncoderTest extends ProtocolTest { command.setDeviceId(1); command.setType(Command.TYPE_ENGINE_STOP); - verifyCommand(encoder, command, binary("40401a00043132333435363738393031323334350000000000834501c7280d0a")); + verifyCommand(encoder, command, binary("40401a00043132333435363738393031323334350000000000458301fe6a0d0a")); } -- cgit v1.2.3 From 38c1ff9bccc1c417a0c2b412271aa7240a3b7db7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 16 Mar 2018 22:57:59 +1300 Subject: Implement Continental RVS protocol --- setup/default.xml | 1 + src/org/traccar/protocol/ContinentalProtocol.java | 43 ++++++++++ .../protocol/ContinentalProtocolDecoder.java | 93 ++++++++++++++++++++++ .../protocol/ContinentalProtocolDecoderTest.java | 25 ++++++ 4 files changed, 162 insertions(+) create mode 100644 src/org/traccar/protocol/ContinentalProtocol.java create mode 100644 src/org/traccar/protocol/ContinentalProtocolDecoder.java create mode 100644 test/org/traccar/protocol/ContinentalProtocolDecoderTest.java (limited to 'test/org') diff --git a/setup/default.xml b/setup/default.xml index 8701ddc4c..68465011e 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -230,5 +230,6 @@ 5158 5159 5160 + 5161 diff --git a/src/org/traccar/protocol/ContinentalProtocol.java b/src/org/traccar/protocol/ContinentalProtocol.java new file mode 100644 index 000000000..e2b1226cf --- /dev/null +++ b/src/org/traccar/protocol/ContinentalProtocol.java @@ -0,0 +1,43 @@ +/* + * 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.protocol; + +import org.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.TrackerServer; + +import java.util.List; + +public class ContinentalProtocol extends BaseProtocol { + + public ContinentalProtocol() { + super("continental"); + } + + @Override + public void initTrackerServers(List serverList) { + serverList.add(new TrackerServer(new ServerBootstrap(), getName()) { + @Override + protected void addSpecificHandlers(ChannelPipeline pipeline) { + pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 2, 2)); + pipeline.addLast("objectDecoder", new ContinentalProtocolDecoder(ContinentalProtocol.this)); + } + }); + } + +} diff --git a/src/org/traccar/protocol/ContinentalProtocolDecoder.java b/src/org/traccar/protocol/ContinentalProtocolDecoder.java new file mode 100644 index 000000000..2138eb39e --- /dev/null +++ b/src/org/traccar/protocol/ContinentalProtocolDecoder.java @@ -0,0 +1,93 @@ +/* + * 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.protocol; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; + +public class ContinentalProtocolDecoder extends BaseProtocolDecoder { + + public ContinentalProtocolDecoder(ContinentalProtocol protocol) { + super(protocol); + } + + public static final int MSG_KEEPALIVE = 0x00; + public static final int MSG_STATUS = 0x02; + public static final int MSG_ACK = 0x06; + public static final int MSG_NACK = 0x15; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ChannelBuffer buf = (ChannelBuffer) msg; + + buf.skipBytes(2); // header + buf.readUnsignedShort(); // length + buf.readUnsignedByte(); // software version + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(buf.readUnsignedInt())); + if (deviceSession == null) { + return null; + } + + buf.readUnsignedByte(); // product + + int type = buf.readUnsignedByte(); + + if (type == MSG_STATUS) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setFixTime(new Date(buf.readUnsignedInt() * 1000L)); + + buf.readUnsignedByte(); + position.setLatitude(buf.readMedium() / 3600.0); + + buf.readUnsignedByte(); + position.setLongitude(buf.readMedium() / 3600.0); + + position.setCourse(buf.readUnsignedShort()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + + position.setValid(buf.readUnsignedByte() > 0); + + position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000L)); + + position.set(Position.KEY_EVENT, buf.readUnsignedShort()); + position.set(Position.KEY_INPUT, buf.readUnsignedShort()); + position.set(Position.KEY_OUTPUT, buf.readUnsignedShort()); + position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); + position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); + + buf.readUnsignedShort(); // reserved + + return position; + + } + + return null; + } + +} diff --git a/test/org/traccar/protocol/ContinentalProtocolDecoderTest.java b/test/org/traccar/protocol/ContinentalProtocolDecoderTest.java new file mode 100644 index 000000000..fbc7c3219 --- /dev/null +++ b/test/org/traccar/protocol/ContinentalProtocolDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ContinentalProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ContinentalProtocolDecoder decoder = new ContinentalProtocolDecoder(new ContinentalProtocol()); + + verifyPosition(decoder, binary( + "5356002A1100003039030243A68B5700FEB5AB00FD715F012700000143A68B57000E000000000C2F00000130"), + position("2005-12-19 10:28:39.000", true, -23.49027, -46.55138)); + + verifyPosition(decoder, binary( + "5356002a0d0010a12403025a9ea47f00feb48400fd6e63000c0000015a9ea480000e000100000c000000")); + + verifyPosition(decoder, binary( + "5356002a0d0010a1240302581b944100febed800fd9fa30139001300581c73fa000e000000000d000001")); + + } + +} -- cgit v1.2.3