From c51119948fcd7b1f77f174310cc1b3cfaa031fd7 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Tue, 2 Jul 2019 23:46:51 -0400 Subject: Enhance Laipac protocol decoder --- .../traccar/protocol/LaipacProtocolDecoder.java | 240 +++++++++++++++++---- 1 file changed, 193 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 2f3cbb1b9..17298c6f3 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -17,6 +17,7 @@ package org.traccar.protocol; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; import org.traccar.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -25,41 +26,57 @@ import org.traccar.helper.DateBuilder; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; import org.traccar.model.CellTower; +import org.traccar.model.Device; +import org.traccar.model.Command; import org.traccar.model.Network; import org.traccar.model.Position; +import org.traccar.database.ConnectionManager; import java.net.SocketAddress; import java.util.regex.Pattern; +import java.util.Date; public class LaipacProtocolDecoder extends BaseProtocolDecoder { + private final String defaultDevicePassword; + public LaipacProtocolDecoder(Protocol protocol) { super(protocol); + defaultDevicePassword = Context.getConfig().getString( + getProtocolName() + ".defaultPassword", "00000000"); } - private static final Pattern PATTERN = new PatternBuilder() - .text("$AVRMC,") - .expression("([^,]+),") // identifier - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([AVRPavrp]),") // validity - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .number("([EW]),") - .number("(d+.d+),") // speed - .number("(d+.d+),") // course - .number("(dd)(dd)(dd),") // date (ddmmyy) - .expression("([abZXTSMHFE86430]),") // event code - .expression("([\\d.]+),") // battery voltage - .number("(d+),") // current mileage - .number("(d),") // gps status - .number("(d+),") // adc1 - .number("(d+)") // adc2 - .number(",(xxxx)") // lac - .number("(xxxx),") // cid - .number("(ddd)") // mcc - .number("(ddd)") // mnc - .optional(4) + private static final Pattern PATTERN_ECHK = new PatternBuilder() + .text("$ECHK") + .expression(",([^,]+)") // identifier + .number(",(d+)") // sequence number + .text("*") + .number("(xx)") // checksum + .compile(); + + private static final Pattern PATTERN_AVRMC = new PatternBuilder() + .text("$AVRMC") + .expression(",([^,]+)") // identifier + .number(",(dd)(dd)(dd)") // time (hhmmss) + .expression(",([AVRPavrp])") // validity + .number(",(dd)(dd.d+)") // latitude + .expression(",([NS])") // latitude hemisphere + .number(",(ddd)(dd.d+)") // longitude + .number(",([EW])") // longitude hemisphere + .number(",(d+.d+)") // speed + .number(",(d+.d+)") // course + .number(",(dd)(dd)(dd)") // date (ddmmyy) + .expression(",([0-9A-Za-z])") // event code + .expression(",([\\d.]+)") // battery voltage + .number(",(d+)") // current mileage + .number(",(d)") // gps status + .number(",(d+)") // adc1 + .number(",(d+)") // adc2 + .number(",(x{1}|x{8})") // lac+cid + .number(",(d{1}|d{6})") // mcc+mnc + .optional(2) + .expression(",([^*]*)") // anything remaining (be forward compatible) + .optional(1) .text("*") .number("(xx)") // checksum .compile(); @@ -68,6 +85,8 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { switch (event) { case "Z": return Position.ALARM_LOW_BATTERY; + case "Y": + return Position.ALARM_TOW; case "X": return Position.ALARM_GEOFENCE_ENTER; case "T": @@ -81,6 +100,8 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return Position.ALARM_GEOFENCE_EXIT; case "6": return Position.ALARM_OVERSPEED; + case "5": + return Position.ALARM_POWER_CUT; case "3": return Position.ALARM_SOS; default: @@ -88,74 +109,157 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { } } - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + private String decodeEvent(String event, Position position) { - String sentence = (String) msg; + if (event.length() == 1) { + char inputStatus = event.charAt(0); + if (inputStatus >= 'A' && inputStatus <= 'D') { + int inputStatusInt = inputStatus - 'A'; + position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); + position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); + position.set(Position.KEY_IGNITION, ((inputStatusInt & 1) != 0) ? true : false); + return null; + } + } - if (sentence.startsWith("$ECHK") && channel != null) { - channel.writeAndFlush(new NetworkMessage(sentence + "\r\n", remoteAddress)); // heartbeat - return null; + return event; + } + + private String getDevicePassword(DeviceSession deviceSession) { + + String devicePassword = defaultDevicePassword; + + Device device = Context.getIdentityManager().getById(deviceSession.getDeviceId()); + if (device != null) { + String password = device.getString(Command.KEY_DEVICE_PASSWORD); + if (password != null) { + devicePassword = password; + } } - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; + return devicePassword; + } + + private Object handleEchk( + String sentence, int checksum, Parser parser, Channel channel, SocketAddress remoteAddress) { + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(sentence + "\r\n", remoteAddress)); } - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + DeviceSession deviceSession = + getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession != null) { + ConnectionManager cm = Context.getConnectionManager(); + if (cm != null) { + cm.updateDevice(deviceSession.getDeviceId(), + Device.STATUS_ONLINE, new Date()); + } + } + + return null; + } + + protected Object handleAvrmc( + String sentence, int checksum, Parser parser, Channel channel, SocketAddress remoteAddress) { + + DeviceSession deviceSession = + getDeviceSession(channel, remoteAddress, parser.next()); if (deviceSession == null) { return null; } Position position = new Position(getProtocolName()); + + // Device ID position.setDeviceId(deviceSession.getDeviceId()); + // Time DateBuilder dateBuilder = new DateBuilder() .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + // Status [ V: Invalid | A: Valid | R: Not realtime | P: Parked ] String status = parser.next(); String upperCaseStatus = status.toUpperCase(); - position.setValid(upperCaseStatus.equals("A") || upperCaseStatus.equals("R") || upperCaseStatus.equals("P")); + position.setValid(upperCaseStatus.equals("A")); position.set(Position.KEY_STATUS, status); + // Position position.setLatitude(parser.nextCoordinate()); position.setLongitude(parser.nextCoordinate()); + + // Speed position.setSpeed(parser.nextDouble(0)); + + // Course position.setCourse(parser.nextDouble(0)); + // Date dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); position.setTime(dateBuilder.getDate()); + // Alarm / Event String event = parser.next(); position.set(Position.KEY_ALARM, decodeAlarm(event)); - position.set(Position.KEY_EVENT, event); + position.set(Position.KEY_EVENT, decodeEvent(event, position)); + + // Battery position.set(Position.KEY_BATTERY, Double.parseDouble(parser.next().replaceAll("\\.", "")) * 0.001); + + // Odometer position.set(Position.KEY_ODOMETER, parser.nextDouble()); + + // GPS status position.set(Position.KEY_GPS, parser.nextInt()); + + // ADC1 / ADC2 position.set(Position.PREFIX_ADC + 1, parser.nextDouble() * 0.001); position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001); - Integer lac = parser.nextHexInt(); - Integer cid = parser.nextHexInt(); - Integer mcc = parser.nextInt(); - Integer mnc = parser.nextInt(); - if (lac != null && cid != null && mcc != null && mnc != null) { + // LAC, CID, MCC, MNC + Integer laccid = parser.nextHexInt(); + Integer mccmnc = parser.nextInt(); + if (laccid != null && laccid != 0 && mccmnc != null && mccmnc != 0) { + Integer lac = (laccid >> 16) & 0xFFFF; + Integer cid = laccid & 0xFFFF; + Integer mcc = mccmnc / 10000; + Integer mnc = mccmnc % 100; position.setNetwork(new Network(CellTower.from(mcc, mnc, lac, cid))); } - String checksum = parser.next(); + // Skip remaining parameters + String unused = parser.next(); + + // Checksum + String checksumStr = parser.next(); + if (checksum != Integer.parseInt(checksumStr, 16)) { + return null; + } if (channel != null) { + + if (Character.isLowerCase(status.charAt(0))) { + String ack = "$EAVACK," + event + "," + checksumStr; + ack += Checksum.nmea(ack) + "\r\n"; + channel.writeAndFlush(new NetworkMessage(ack, remoteAddress)); + } + + String response = ""; + String devicePassword = getDevicePassword(deviceSession); + if (event.equals("3")) { - channel.writeAndFlush(new NetworkMessage("$AVCFG,00000000,d*31\r\n", remoteAddress)); + response = "$AVCFG," + devicePassword + ",d"; + } else if (event.equals("S") || event.equals("T")) { + response = "$AVCFG," + devicePassword + ",t"; } else if (event.equals("X") || event.equals("4")) { - channel.writeAndFlush(new NetworkMessage("$AVCFG,00000000,x*2D\r\n", remoteAddress)); + response = "$AVCFG," + devicePassword + ",x"; + } else if (event.equals("Y")) { + response = "$AVCFG," + devicePassword + ",y"; } else if (event.equals("Z")) { - channel.writeAndFlush(new NetworkMessage("$AVCFG,00000000,z*2F\r\n", remoteAddress)); - } else if (Character.isLowerCase(status.charAt(0))) { - String response = "$EAVACK," + event + "," + checksum; + response = "$AVCFG," + devicePassword + ",z"; + } + + if (response.length() > 0) { response += Checksum.nmea(response) + "\r\n"; channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } @@ -164,4 +268,46 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return position; } + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + // Validate sentence length + int slen = sentence.length(); + if (slen <= 5) { + return null; + } + + // Validate sentence format + if (sentence.charAt(0) != '$') { + return null; + } + if (sentence.charAt(slen - 3) != '*') { + return null; + } + + // Verify sentence checksum + int checksum = Integer.parseInt(sentence.substring(slen - 2), 16); + if (checksum != Checksum.xor(sentence.substring(1, slen - 3))) { + return null; + } + + // Handle ECHK sentences + Parser parser = new Parser(PATTERN_ECHK, sentence); + if (parser.matches()) { + return handleEchk(sentence, checksum, parser, channel, remoteAddress); + } + + // Handle AVRMC sentences + parser = new Parser(PATTERN_AVRMC, sentence); + if (parser.matches()) { + return handleAvrmc(sentence, checksum, parser, channel, remoteAddress); + } + + return null; + } + + } -- cgit v1.2.3 From 53871f6f1ed5d40a6895dd6d84fb5d201a9110a3 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Tue, 2 Jul 2019 23:47:55 -0400 Subject: Add Laipac protocol decoder tests --- .../org/traccar/protocol/LaipacProtocolDecoderTest.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java index 31a0434bc..1426e5c35 100644 --- a/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java @@ -15,10 +15,10 @@ public class LaipacProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, text( "$AVSYS,99999999,V1.50,SN0000103,32768*15")); - + verifyNull(decoder, text( "$ECHK,99999999,0*35")); - + verifyNull(decoder, text( "$AVSYS,MSG00002,14406,7046811160,64*1A")); @@ -85,10 +85,10 @@ public class LaipacProtocolDecoderTest extends ProtocolTest { verifyPosition(decoder, text( "$AVRMC,MSG00002,125517,R,5053.0442,N,00557.8694,E,0.00,0.00,240614,H,4076,167,1,0,0,0D7AB913,020408*75")); - + verifyPosition(decoder, text( "$AVRMC,MSG00002,043104,p,5114.4664,N,00534.3308,E,0.00,0.00,280614,0,4115,495,1,0,0,0D48C3DC,020408*52")); - + verifyPosition(decoder, text( "$AVRMC,MSG00002,050601,P,5114.4751,N,00534.3175,E,0.00,0.00,280614,0,4115,495,1,0,0,0D48C3DC,020408*7D")); @@ -120,6 +120,13 @@ public class LaipacProtocolDecoderTest extends ProtocolTest { verifyPosition(decoder, text( "$AVRMC,358174067149865,143747,R,5050.1124,N,00420.0542,E,1.34,161.96,190318,a,3416,119,1,0,0*7D")); + //Zero LAC, CID, MCC, MNC + verifyPosition(decoder, text( + "$AVRMC,358174067149865,143747,P,5050.1124,N,00420.0542,E,1.34,161.96,190318,A,3416,119,1,0,0,0,0*5F")); + + //New unknown parameters + verifyPosition(decoder, text( + "$AVRMC,358174067149865,143747,P,5050.1124,N,00420.0542,E,1.34,161.96,190318,A,3416,119,1,0,0,0,0,0,0*5F")); } } -- cgit v1.2.3 From efb64c30835eccf1e532ea7d7618d2d40ce7b761 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Tue, 2 Jul 2019 23:48:54 -0400 Subject: Implement basic Laipac protocol encoder --- .../java/org/traccar/protocol/LaipacProtocol.java | 8 +++ .../traccar/protocol/LaipacProtocolEncoder.java | 71 ++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java diff --git a/src/main/java/org/traccar/protocol/LaipacProtocol.java b/src/main/java/org/traccar/protocol/LaipacProtocol.java index 923b08a16..601e652c4 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocol.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocol.java @@ -18,6 +18,7 @@ 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.model.Command; import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; @@ -25,12 +26,19 @@ import org.traccar.TrackerServer; public class LaipacProtocol extends BaseProtocol { public LaipacProtocol() { + + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_POSITION_SINGLE, + Command.TYPE_REBOOT_DEVICE); + 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 LaipacProtocolEncoder(LaipacProtocol.this)); pipeline.addLast(new LaipacProtocolDecoder(LaipacProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java new file mode 100644 index 000000000..090203806 --- /dev/null +++ b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java @@ -0,0 +1,71 @@ +/* + * Copyright 2015 - 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 org.traccar.Context; +import org.traccar.Protocol; +import org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; +import org.traccar.helper.Checksum; + +public class LaipacProtocolEncoder extends StringProtocolEncoder { + + private final Protocol protocol; + private final String defaultDevicePassword; + + public LaipacProtocolEncoder(Protocol protocol) { + this.protocol = protocol; + defaultDevicePassword = Context.getConfig().getString( + getProtocolName() + ".defaultPassword", "00000000"); + } + + protected String getProtocolName() { + return protocol.getName(); + } + + @Override + protected Object encodeCommand(Command command) { + + initDevicePassword(command, defaultDevicePassword); + + String cmd = ""; + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + cmd = formatCommand(command, "${%s}", + Command.KEY_DATA); + break; + case Command.TYPE_POSITION_SINGLE: + cmd = formatCommand(command, "$AVREQ,{%s},1", + Command.KEY_DEVICE_PASSWORD); + break; + case Command.TYPE_REBOOT_DEVICE: + cmd = formatCommand(command, "$AVRESET,{%s},{%s}", + Command.KEY_UNIQUE_ID, Command.KEY_DEVICE_PASSWORD); + break; + default: + break; + } + + if (cmd.length() > 0) { + cmd += Checksum.nmea(cmd) + "\r\n"; + return cmd; + } + + return null; + } + +} -- cgit v1.2.3 From 9cd863136dbcf9e8062f633869de212426bed960 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Wed, 3 Jul 2019 17:04:36 -0400 Subject: Changes after first review --- .../traccar/protocol/LaipacProtocolDecoder.java | 164 +++++++++------------ .../traccar/protocol/LaipacProtocolEncoder.java | 20 ++- .../protocol/LaipacProtocolDecoderTest.java | 12 +- 3 files changed, 83 insertions(+), 113 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 17298c6f3..544f1dc80 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -30,11 +30,9 @@ import org.traccar.model.Device; import org.traccar.model.Command; import org.traccar.model.Network; import org.traccar.model.Position; -import org.traccar.database.ConnectionManager; import java.net.SocketAddress; import java.util.regex.Pattern; -import java.util.Date; public class LaipacProtocolDecoder extends BaseProtocolDecoder { @@ -72,9 +70,11 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { .number(",(d)") // gps status .number(",(d+)") // adc1 .number(",(d+)") // adc2 - .number(",(x{1}|x{8})") // lac+cid - .number(",(d{1}|d{6})") // mcc+mnc - .optional(2) + .number(",(x{4}|x{1})") // lac | lac+cid = 0 + .number("(x{4})") // cid | nothing + .number(",(d{3}|d{1})") // mcc | mcc+mnc = 0 + .number("(d{3})") // mnc | nothing + .optional(4) .expression(",([^*]*)") // anything remaining (be forward compatible) .optional(1) .text("*") @@ -140,28 +140,64 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return devicePassword; } + private String getEventResponse(String event, String devicePassword) { + + String responseCode = null; + + switch (event) { + case "3": + responseCode = "d"; + break; + case "S": + case "T": + responseCode = "t"; + break; + case "X": + case "4": + responseCode = "x"; + break; + case "Y": + responseCode = "y"; + break; + case "Z": + responseCode = "z"; + break; + default: + break; + } + + if (responseCode != null) { + String response = "$AVCFG," + devicePassword + "," + responseCode; + response += Checksum.nmea(response) + "\r\n"; + return response; + } + + return null; + } + + private String getStatusResponse(String status, String event, String checksum) { + + if (Character.isLowerCase(status.charAt(0))) { + String response = "$EAVACK," + event + "," + checksum; + response += Checksum.nmea(response) + "\r\n"; + return response; + } + + return null; + } + private Object handleEchk( - String sentence, int checksum, Parser parser, Channel channel, SocketAddress remoteAddress) { + String sentence, Parser parser, Channel channel, SocketAddress remoteAddress) { if (channel != null) { channel.writeAndFlush(new NetworkMessage(sentence + "\r\n", remoteAddress)); } - DeviceSession deviceSession = - getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession != null) { - ConnectionManager cm = Context.getConnectionManager(); - if (cm != null) { - cm.updateDevice(deviceSession.getDeviceId(), - Device.STATUS_ONLINE, new Date()); - } - } - return null; } protected Object handleAvrmc( - String sentence, int checksum, Parser parser, Channel channel, SocketAddress remoteAddress) { + String sentence, Parser parser, Channel channel, SocketAddress remoteAddress) { DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); @@ -171,97 +207,55 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); - // Device ID position.setDeviceId(deviceSession.getDeviceId()); - - // Time DateBuilder dateBuilder = new DateBuilder() .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - // Status [ V: Invalid | A: Valid | R: Not realtime | P: Parked ] String status = parser.next(); String upperCaseStatus = status.toUpperCase(); - position.setValid(upperCaseStatus.equals("A")); + position.setValid(upperCaseStatus.equals("A") || upperCaseStatus.equals("R") || upperCaseStatus.equals("P")); position.set(Position.KEY_STATUS, status); - // Position position.setLatitude(parser.nextCoordinate()); position.setLongitude(parser.nextCoordinate()); - - // Speed position.setSpeed(parser.nextDouble(0)); - - // Course position.setCourse(parser.nextDouble(0)); - // Date dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); position.setTime(dateBuilder.getDate()); - // Alarm / Event String event = parser.next(); position.set(Position.KEY_ALARM, decodeAlarm(event)); position.set(Position.KEY_EVENT, decodeEvent(event, position)); - - // Battery position.set(Position.KEY_BATTERY, Double.parseDouble(parser.next().replaceAll("\\.", "")) * 0.001); - - // Odometer position.set(Position.KEY_ODOMETER, parser.nextDouble()); - - // GPS status position.set(Position.KEY_GPS, parser.nextInt()); - - // ADC1 / ADC2 position.set(Position.PREFIX_ADC + 1, parser.nextDouble() * 0.001); position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001); - // LAC, CID, MCC, MNC - Integer laccid = parser.nextHexInt(); - Integer mccmnc = parser.nextInt(); - if (laccid != null && laccid != 0 && mccmnc != null && mccmnc != 0) { - Integer lac = (laccid >> 16) & 0xFFFF; - Integer cid = laccid & 0xFFFF; - Integer mcc = mccmnc / 10000; - Integer mnc = mccmnc % 100; + Integer lac = parser.nextHexInt(); + Integer cid = parser.nextHexInt(); + Integer mcc = parser.nextInt(); + Integer mnc = parser.nextInt(); + if (lac != null && cid != null && mcc != null && mnc != null) { position.setNetwork(new Network(CellTower.from(mcc, mnc, lac, cid))); } - // Skip remaining parameters String unused = parser.next(); - // Checksum - String checksumStr = parser.next(); - if (checksum != Integer.parseInt(checksumStr, 16)) { - return null; - } + String checksum = parser.next(); if (channel != null) { - if (Character.isLowerCase(status.charAt(0))) { - String ack = "$EAVACK," + event + "," + checksumStr; - ack += Checksum.nmea(ack) + "\r\n"; - channel.writeAndFlush(new NetworkMessage(ack, remoteAddress)); + String statusResponse = getStatusResponse(status, event, checksum); + if (statusResponse != null) { + channel.writeAndFlush(new NetworkMessage(statusResponse, remoteAddress)); } - String response = ""; String devicePassword = getDevicePassword(deviceSession); - - if (event.equals("3")) { - response = "$AVCFG," + devicePassword + ",d"; - } else if (event.equals("S") || event.equals("T")) { - response = "$AVCFG," + devicePassword + ",t"; - } else if (event.equals("X") || event.equals("4")) { - response = "$AVCFG," + devicePassword + ",x"; - } else if (event.equals("Y")) { - response = "$AVCFG," + devicePassword + ",y"; - } else if (event.equals("Z")) { - response = "$AVCFG," + devicePassword + ",z"; - } - - if (response.length() > 0) { - response += Checksum.nmea(response) + "\r\n"; - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + String eventResponse = getEventResponse(event, devicePassword); + if (eventResponse != null) { + channel.writeAndFlush(new NetworkMessage(eventResponse, remoteAddress)); } } @@ -274,36 +268,14 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { String sentence = (String) msg; - // Validate sentence length - int slen = sentence.length(); - if (slen <= 5) { - return null; - } - - // Validate sentence format - if (sentence.charAt(0) != '$') { - return null; - } - if (sentence.charAt(slen - 3) != '*') { - return null; - } - - // Verify sentence checksum - int checksum = Integer.parseInt(sentence.substring(slen - 2), 16); - if (checksum != Checksum.xor(sentence.substring(1, slen - 3))) { - return null; - } - - // Handle ECHK sentences Parser parser = new Parser(PATTERN_ECHK, sentence); if (parser.matches()) { - return handleEchk(sentence, checksum, parser, channel, remoteAddress); + return handleEchk(sentence, parser, channel, remoteAddress); } - // Handle AVRMC sentences parser = new Parser(PATTERN_AVRMC, sentence); if (parser.matches()) { - return handleAvrmc(sentence, checksum, parser, channel, remoteAddress); + return handleAvrmc(sentence, parser, channel, remoteAddress); } return null; diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java index 090203806..fac82d2fd 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org) + * 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. @@ -15,7 +15,6 @@ */ package org.traccar.protocol; -import org.traccar.Context; import org.traccar.Protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; @@ -28,8 +27,7 @@ public class LaipacProtocolEncoder extends StringProtocolEncoder { public LaipacProtocolEncoder(Protocol protocol) { this.protocol = protocol; - defaultDevicePassword = Context.getConfig().getString( - getProtocolName() + ".defaultPassword", "00000000"); + defaultDevicePassword = "00000000"; } protected String getProtocolName() { @@ -41,28 +39,28 @@ public class LaipacProtocolEncoder extends StringProtocolEncoder { initDevicePassword(command, defaultDevicePassword); - String cmd = ""; + String commandSentence = null; switch (command.getType()) { case Command.TYPE_CUSTOM: - cmd = formatCommand(command, "${%s}", + commandSentence = formatCommand(command, "${%s}", Command.KEY_DATA); break; case Command.TYPE_POSITION_SINGLE: - cmd = formatCommand(command, "$AVREQ,{%s},1", + commandSentence = formatCommand(command, "$AVREQ,{%s},1", Command.KEY_DEVICE_PASSWORD); break; case Command.TYPE_REBOOT_DEVICE: - cmd = formatCommand(command, "$AVRESET,{%s},{%s}", + commandSentence = formatCommand(command, "$AVRESET,{%s},{%s}", Command.KEY_UNIQUE_ID, Command.KEY_DEVICE_PASSWORD); break; default: break; } - if (cmd.length() > 0) { - cmd += Checksum.nmea(cmd) + "\r\n"; - return cmd; + if (commandSentence != null) { + commandSentence += Checksum.nmea(commandSentence) + "\r\n"; + return commandSentence; } return null; diff --git a/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java index 1426e5c35..0bbb58490 100644 --- a/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java @@ -104,27 +104,27 @@ public class LaipacProtocolDecoderTest extends ProtocolTest { verifyPosition(decoder, text( "$AVRMC,999999999999999,084514,r,5050.1314,N,00419.9719,E,0.68,306.39,120318,0,3882,84,1,0,0,3EE4A617,020610*4D")); - //Alarm button + // Alarm button verifyPosition(decoder, text( "$AVRMC,358174067149865,142945,R,5050.1254,N,00420.0490,E,0.00,0.00,190318,3,3455,119,1,0,0,3EE4A617,020610*53")); - //G-Sensor + // G-Sensor verifyPosition(decoder, text( "$AVRMC,358174067149865,143407,R,5050.1254,N,00420.0490,E,0.00,0.00,190318,8,3455,119,1,0,0,3EE4A617,020610*52")); - //Powered off + // Powered off verifyPosition(decoder, text( "$AVRMC,358174067149865,143648,A,5050.1141,N,00420.0525,E,1.24,174.38,190318,H,3455,119,1,0,0,3EE4A617,020610*3E")); - //No network + // No network verifyPosition(decoder, text( "$AVRMC,358174067149865,143747,R,5050.1124,N,00420.0542,E,1.34,161.96,190318,a,3416,119,1,0,0*7D")); - //Zero LAC, CID, MCC, MNC + // Zero LAC, CID, MCC, MNC verifyPosition(decoder, text( "$AVRMC,358174067149865,143747,P,5050.1124,N,00420.0542,E,1.34,161.96,190318,A,3416,119,1,0,0,0,0*5F")); - //New unknown parameters + // New unknown parameters verifyPosition(decoder, text( "$AVRMC,358174067149865,143747,P,5050.1124,N,00420.0542,E,1.34,161.96,190318,A,3416,119,1,0,0,0,0,0,0*5F")); } -- cgit v1.2.3 From 0e4e396fee573aa8d00a0f970085266ffdb45e93 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Thu, 4 Jul 2019 12:22:13 -0400 Subject: Missed minor change --- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 544f1dc80..b8a0b167c 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -40,8 +40,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { public LaipacProtocolDecoder(Protocol protocol) { super(protocol); - defaultDevicePassword = Context.getConfig().getString( - getProtocolName() + ".defaultPassword", "00000000"); + defaultDevicePassword = "00000000"; } private static final Pattern PATTERN_ECHK = new PatternBuilder() -- cgit v1.2.3 From 11568839d89fa5bf58da0a654248f9b7696ee406 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Fri, 5 Jul 2019 02:42:01 -0400 Subject: Changes after second review --- .../java/org/traccar/protocol/LaipacProtocol.java | 4 +- .../traccar/protocol/LaipacProtocolDecoder.java | 73 ++++++++++------------ .../traccar/protocol/LaipacProtocolEncoder.java | 14 +---- 3 files changed, 37 insertions(+), 54 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocol.java b/src/main/java/org/traccar/protocol/LaipacProtocol.java index 601e652c4..b325755c8 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocol.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -38,7 +38,7 @@ public class LaipacProtocol extends BaseProtocol { pipeline.addLast(new LineBasedFrameDecoder(1024)); pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder()); - pipeline.addLast(new LaipacProtocolEncoder(LaipacProtocol.this)); + pipeline.addLast(new LaipacProtocolEncoder()); pipeline.addLast(new LaipacProtocolDecoder(LaipacProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index b8a0b167c..c028d78b6 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2019 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,13 +36,12 @@ import java.util.regex.Pattern; public class LaipacProtocolDecoder extends BaseProtocolDecoder { - private final String defaultDevicePassword; - public LaipacProtocolDecoder(Protocol protocol) { super(protocol); - defaultDevicePassword = "00000000"; } + public static final String DEFAULT_DEVICE_PASSWORD = "00000000"; + private static final Pattern PATTERN_ECHK = new PatternBuilder() .text("$ECHK") .expression(",([^,]+)") // identifier @@ -52,27 +51,27 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { .compile(); private static final Pattern PATTERN_AVRMC = new PatternBuilder() - .text("$AVRMC") - .expression(",([^,]+)") // identifier - .number(",(dd)(dd)(dd)") // time (hhmmss) - .expression(",([AVRPavrp])") // validity - .number(",(dd)(dd.d+)") // latitude - .expression(",([NS])") // latitude hemisphere - .number(",(ddd)(dd.d+)") // longitude - .number(",([EW])") // longitude hemisphere - .number(",(d+.d+)") // speed - .number(",(d+.d+)") // course - .number(",(dd)(dd)(dd)") // date (ddmmyy) - .expression(",([0-9A-Za-z])") // event code - .expression(",([\\d.]+)") // battery voltage - .number(",(d+)") // current mileage - .number(",(d)") // gps status - .number(",(d+)") // adc1 - .number(",(d+)") // adc2 - .number(",(x{4}|x{1})") // lac | lac+cid = 0 - .number("(x{4})") // cid | nothing - .number(",(d{3}|d{1})") // mcc | mcc+mnc = 0 - .number("(d{3})") // mnc | nothing + .text("$AVRMC,") + .expression("([^,]+),") // identifier + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AVRPavrp]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") // latitude hemisphere + .number("(ddd)(dd.d+),") // longitude + .number("([EW]),") // longitude hemisphere + .number("(d+.d+),") // speed + .number("(d+.d+),") // course + .number("(dd)(dd)(dd),") // date (ddmmyy) + .expression("([0-9A-Za-z]),") // event code + .expression("([\\d.]+),") // battery voltage + .number("(d+),") // current mileage + .number("(d),") // gps status + .number("(d+),") // adc1 + .number("(d+)") // adc2 + .number(",(xxxx|x)") // lac | lac+cid = 0 + .number("(xxxx),") // cid | nothing + .number("(ddd|d)") // mcc | mcc+mnc = 0 + .number("(ddd)") // mnc | nothing .optional(4) .expression(",([^*]*)") // anything remaining (be forward compatible) .optional(1) @@ -126,7 +125,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { private String getDevicePassword(DeviceSession deviceSession) { - String devicePassword = defaultDevicePassword; + String devicePassword = DEFAULT_DEVICE_PASSWORD; Device device = Context.getIdentityManager().getById(deviceSession.getDeviceId()); if (device != null) { @@ -139,7 +138,8 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return devicePassword; } - private String getEventResponse(String event, String devicePassword) { + private void sendEventResponse( + String event, String devicePassword, Channel channel, SocketAddress remoteAddress) { String responseCode = null; @@ -168,21 +168,20 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { if (responseCode != null) { String response = "$AVCFG," + devicePassword + "," + responseCode; response += Checksum.nmea(response) + "\r\n"; - return response; + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } - return null; } - private String getStatusResponse(String status, String event, String checksum) { + private void sendAcknowledge( + String status, String event, String checksum, Channel channel, SocketAddress remoteAddress) { if (Character.isLowerCase(status.charAt(0))) { String response = "$EAVACK," + event + "," + checksum; response += Checksum.nmea(response) + "\r\n"; - return response; + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } - return null; } private Object handleEchk( @@ -246,16 +245,10 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { if (channel != null) { - String statusResponse = getStatusResponse(status, event, checksum); - if (statusResponse != null) { - channel.writeAndFlush(new NetworkMessage(statusResponse, remoteAddress)); - } + sendAcknowledge(status, event, checksum, channel, remoteAddress); String devicePassword = getDevicePassword(deviceSession); - String eventResponse = getEventResponse(event, devicePassword); - if (eventResponse != null) { - channel.writeAndFlush(new NetworkMessage(eventResponse, remoteAddress)); - } + sendEventResponse(event, devicePassword, channel, remoteAddress); } return position; diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java index fac82d2fd..6f540fa3e 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java @@ -15,29 +15,19 @@ */ package org.traccar.protocol; -import org.traccar.Protocol; import org.traccar.StringProtocolEncoder; import org.traccar.model.Command; import org.traccar.helper.Checksum; public class LaipacProtocolEncoder extends StringProtocolEncoder { - private final Protocol protocol; - private final String defaultDevicePassword; - - public LaipacProtocolEncoder(Protocol protocol) { - this.protocol = protocol; - defaultDevicePassword = "00000000"; - } - - protected String getProtocolName() { - return protocol.getName(); + public LaipacProtocolEncoder() { } @Override protected Object encodeCommand(Command command) { - initDevicePassword(command, defaultDevicePassword); + initDevicePassword(command, LaipacProtocolDecoder.DEFAULT_DEVICE_PASSWORD); String commandSentence = null; -- cgit v1.2.3 From 2c604b9c9ee8f996902acfdd60626324a8414d34 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Wed, 10 Jul 2019 17:03:25 -0400 Subject: Changes after third review --- src/main/java/org/traccar/BaseProtocolEncoder.java | 13 +++----- .../java/org/traccar/database/DeviceManager.java | 18 +++++++++- .../java/org/traccar/database/IdentityManager.java | 6 +++- .../traccar/protocol/LaipacProtocolDecoder.java | 39 +++++++--------------- .../traccar/protocol/LaipacProtocolEncoder.java | 22 +++++------- src/test/java/org/traccar/TestIdentityManager.java | 8 +++++ 6 files changed, 54 insertions(+), 52 deletions(-) diff --git a/src/main/java/org/traccar/BaseProtocolEncoder.java b/src/main/java/org/traccar/BaseProtocolEncoder.java index d7625e4b8..6d96280f7 100644 --- a/src/main/java/org/traccar/BaseProtocolEncoder.java +++ b/src/main/java/org/traccar/BaseProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -22,7 +22,6 @@ import io.netty.channel.ChannelPromise; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.model.Command; -import org.traccar.model.Device; public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter { @@ -34,13 +33,9 @@ public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter protected void initDevicePassword(Command command, String defaultPassword) { if (!command.getAttributes().containsKey(Command.KEY_DEVICE_PASSWORD)) { - Device device = Context.getIdentityManager().getById(command.getDeviceId()); - String password = device.getString(Command.KEY_DEVICE_PASSWORD); - if (password != null) { - command.set(Command.KEY_DEVICE_PASSWORD, password); - } else { - command.set(Command.KEY_DEVICE_PASSWORD, defaultPassword); - } + String password = Context.getIdentityManager() + .getDevicePassword(command.getDeviceId(), defaultPassword); + command.set(Command.KEY_DEVICE_PASSWORD, password); } } diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index de4607d1f..d1a205b01 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 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. @@ -29,6 +29,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.Context; +import org.traccar.model.Command; import org.traccar.model.Device; import org.traccar.model.DeviceState; import org.traccar.model.DeviceAccumulators; @@ -114,6 +115,21 @@ public class DeviceManager extends BaseObjectManager implements Identity return devicesByUniqueId.get(uniqueId); } + public String getDevicePassword(long id) { + + return getById(id).getString(Command.KEY_DEVICE_PASSWORD); + } + + public String getDevicePassword(long id, String defaultPassword) { + + String password = getDevicePassword(id); + if (password != null) { + return password; + } + + return defaultPassword; + } + public Device getDeviceByPhone(String phone) { return devicesByPhone.get(phone); } diff --git a/src/main/java/org/traccar/database/IdentityManager.java b/src/main/java/org/traccar/database/IdentityManager.java index 6228a0f75..331706669 100644 --- a/src/main/java/org/traccar/database/IdentityManager.java +++ b/src/main/java/org/traccar/database/IdentityManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -26,6 +26,10 @@ public interface IdentityManager { Device getByUniqueId(String uniqueId) throws Exception; + String getDevicePassword(long id); + + String getDevicePassword(long id, String defaultPassword); + Position getLastPosition(long deviceId); boolean isLatestPosition(Position position); diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index c028d78b6..381f497e4 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -26,8 +26,6 @@ import org.traccar.helper.DateBuilder; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; import org.traccar.model.CellTower; -import org.traccar.model.Device; -import org.traccar.model.Command; import org.traccar.model.Network; import org.traccar.model.Position; @@ -123,21 +121,6 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return event; } - private String getDevicePassword(DeviceSession deviceSession) { - - String devicePassword = DEFAULT_DEVICE_PASSWORD; - - Device device = Context.getIdentityManager().getById(deviceSession.getDeviceId()); - if (device != null) { - String password = device.getString(Command.KEY_DEVICE_PASSWORD); - if (password != null) { - devicePassword = password; - } - } - - return devicePassword; - } - private void sendEventResponse( String event, String devicePassword, Channel channel, SocketAddress remoteAddress) { @@ -247,7 +230,8 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { sendAcknowledge(status, event, checksum, channel, remoteAddress); - String devicePassword = getDevicePassword(deviceSession); + String devicePassword = Context.getIdentityManager() + .getDevicePassword(deviceSession.getDeviceId(), DEFAULT_DEVICE_PASSWORD); sendEventResponse(event, devicePassword, channel, remoteAddress); } @@ -260,18 +244,19 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { String sentence = (String) msg; - Parser parser = new Parser(PATTERN_ECHK, sentence); - if (parser.matches()) { - return handleEchk(sentence, parser, channel, remoteAddress); - } - - parser = new Parser(PATTERN_AVRMC, sentence); - if (parser.matches()) { - return handleAvrmc(sentence, parser, channel, remoteAddress); + if (sentence.startsWith("$ECHK")) { + Parser parser = new Parser(PATTERN_ECHK, sentence); + if (parser.matches()) { + return handleEchk(sentence, parser, channel, remoteAddress); + } + } else if (sentence.startsWith("$AVRMC")) { + Parser parser = new Parser(PATTERN_AVRMC, sentence); + if (parser.matches()) { + return handleAvrmc(sentence, parser, channel, remoteAddress); + } } return null; } - } diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java index 6f540fa3e..9b99486f7 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java @@ -21,7 +21,11 @@ import org.traccar.helper.Checksum; public class LaipacProtocolEncoder extends StringProtocolEncoder { - public LaipacProtocolEncoder() { + @Override + protected String formatCommand(Command command, String format, String... keys) { + String sentence = super.formatCommand(command, "$" + format, keys); + sentence += Checksum.nmea(sentence) + "\r\n"; + return sentence; } @Override @@ -29,30 +33,20 @@ public class LaipacProtocolEncoder extends StringProtocolEncoder { initDevicePassword(command, LaipacProtocolDecoder.DEFAULT_DEVICE_PASSWORD); - String commandSentence = null; - switch (command.getType()) { case Command.TYPE_CUSTOM: - commandSentence = formatCommand(command, "${%s}", + return formatCommand(command, "{%s}", Command.KEY_DATA); - break; case Command.TYPE_POSITION_SINGLE: - commandSentence = formatCommand(command, "$AVREQ,{%s},1", + return formatCommand(command, "AVREQ,{%s},1", Command.KEY_DEVICE_PASSWORD); - break; case Command.TYPE_REBOOT_DEVICE: - commandSentence = formatCommand(command, "$AVRESET,{%s},{%s}", + return formatCommand(command, "AVRESET,{%s},{%s}", Command.KEY_UNIQUE_ID, Command.KEY_DEVICE_PASSWORD); - break; default: break; } - if (commandSentence != null) { - commandSentence += Checksum.nmea(commandSentence) + "\r\n"; - return commandSentence; - } - return null; } diff --git a/src/test/java/org/traccar/TestIdentityManager.java b/src/test/java/org/traccar/TestIdentityManager.java index 0f7405dbd..1f7867875 100644 --- a/src/test/java/org/traccar/TestIdentityManager.java +++ b/src/test/java/org/traccar/TestIdentityManager.java @@ -29,6 +29,14 @@ public final class TestIdentityManager implements IdentityManager { return createDevice(); } + public String getDevicePassword(long id) { + return null; + } + + public String getDevicePassword(long id, String defaultPassword) { + return defaultPassword; + } + @Override public Position getLastPosition(long deviceId) { return null; -- cgit v1.2.3 From 0064dec35205fba7b1c8e6c1c0553407688055a8 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Wed, 10 Jul 2019 18:11:13 -0400 Subject: Changes after fourth review --- .../java/org/traccar/database/DeviceManager.java | 7 +---- .../java/org/traccar/database/IdentityManager.java | 2 -- .../traccar/protocol/LaipacProtocolDecoder.java | 31 +++++++++++++--------- .../traccar/protocol/LaipacProtocolEncoder.java | 3 +-- 4 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index d1a205b01..231be7b07 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -115,14 +115,9 @@ public class DeviceManager extends BaseObjectManager implements Identity return devicesByUniqueId.get(uniqueId); } - public String getDevicePassword(long id) { - - return getById(id).getString(Command.KEY_DEVICE_PASSWORD); - } - public String getDevicePassword(long id, String defaultPassword) { - String password = getDevicePassword(id); + String password = getById(id).getString(Command.KEY_DEVICE_PASSWORD); if (password != null) { return password; } diff --git a/src/main/java/org/traccar/database/IdentityManager.java b/src/main/java/org/traccar/database/IdentityManager.java index 331706669..add3e5a79 100644 --- a/src/main/java/org/traccar/database/IdentityManager.java +++ b/src/main/java/org/traccar/database/IdentityManager.java @@ -26,8 +26,6 @@ public interface IdentityManager { Device getByUniqueId(String uniqueId) throws Exception; - String getDevicePassword(long id); - String getDevicePassword(long id, String defaultPassword); Position getLastPosition(long deviceId); diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 381f497e4..3eecf58a3 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -167,8 +167,13 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { } - private Object handleEchk( - String sentence, Parser parser, Channel channel, SocketAddress remoteAddress) { + private Object decodeEchk( + String sentence, Channel channel, SocketAddress remoteAddress) { + + Parser parser = new Parser(PATTERN_ECHK, sentence); + if (!parser.matches()) { + return null; + } if (channel != null) { channel.writeAndFlush(new NetworkMessage(sentence + "\r\n", remoteAddress)); @@ -177,8 +182,13 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { return null; } - protected Object handleAvrmc( - String sentence, Parser parser, Channel channel, SocketAddress remoteAddress) { + protected Object decodeAvrmc( + String sentence, Channel channel, SocketAddress remoteAddress) { + + Parser parser = new Parser(PATTERN_AVRMC, sentence); + if (!parser.matches()) { + return null; + } DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); @@ -245,15 +255,10 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { String sentence = (String) msg; if (sentence.startsWith("$ECHK")) { - Parser parser = new Parser(PATTERN_ECHK, sentence); - if (parser.matches()) { - return handleEchk(sentence, parser, channel, remoteAddress); - } - } else if (sentence.startsWith("$AVRMC")) { - Parser parser = new Parser(PATTERN_AVRMC, sentence); - if (parser.matches()) { - return handleAvrmc(sentence, parser, channel, remoteAddress); - } + return decodeEchk(sentence, channel, remoteAddress); + } + if (sentence.startsWith("$AVRMC")) { + return decodeAvrmc(sentence, channel, remoteAddress); } return null; diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java index 9b99486f7..dec76b83c 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java @@ -44,10 +44,9 @@ public class LaipacProtocolEncoder extends StringProtocolEncoder { return formatCommand(command, "AVRESET,{%s},{%s}", Command.KEY_UNIQUE_ID, Command.KEY_DEVICE_PASSWORD); default: - break; + return null; } - return null; } } -- cgit v1.2.3 From 9990000d67907cb41bdc18639d7dbe081c363f09 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Wed, 10 Jul 2019 21:29:27 -0400 Subject: Fixed not receiving ignition off event --- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 3eecf58a3..767d70a5c 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -107,13 +107,17 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { private String decodeEvent(String event, Position position) { + position.set(Position.KEY_IGNITION, false); + if (event.length() == 1) { char inputStatus = event.charAt(0); if (inputStatus >= 'A' && inputStatus <= 'D') { int inputStatusInt = inputStatus - 'A'; position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); - position.set(Position.KEY_IGNITION, ((inputStatusInt & 1) != 0) ? true : false); + if ((inputStatusInt & 1) != 0) { + position.set(Position.KEY_IGNITION, true); + } return null; } } -- cgit v1.2.3 From 35b6dc85f8c0c23ede5ece005bdc893c4320b8f3 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Wed, 10 Jul 2019 22:00:50 -0400 Subject: Fixed odometer value read as meters instead of kilometers --- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 767d70a5c..c3b12aa80 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -223,7 +223,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ALARM, decodeAlarm(event)); position.set(Position.KEY_EVENT, decodeEvent(event, position)); position.set(Position.KEY_BATTERY, Double.parseDouble(parser.next().replaceAll("\\.", "")) * 0.001); - position.set(Position.KEY_ODOMETER, parser.nextDouble()); + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); position.set(Position.KEY_GPS, parser.nextInt()); position.set(Position.PREFIX_ADC + 1, parser.nextDouble() * 0.001); position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001); -- cgit v1.2.3 From c00703abad85ae27dbd26ffffd6908813bcb5e49 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Thu, 11 Jul 2019 02:39:05 -0400 Subject: Changes after fifth review --- src/main/java/org/traccar/database/DeviceManager.java | 1 + src/test/java/org/traccar/TestIdentityManager.java | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index 231be7b07..62e6de080 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -115,6 +115,7 @@ public class DeviceManager extends BaseObjectManager implements Identity return devicesByUniqueId.get(uniqueId); } + @Override public String getDevicePassword(long id, String defaultPassword) { String password = getById(id).getString(Command.KEY_DEVICE_PASSWORD); diff --git a/src/test/java/org/traccar/TestIdentityManager.java b/src/test/java/org/traccar/TestIdentityManager.java index 1f7867875..98297c53c 100644 --- a/src/test/java/org/traccar/TestIdentityManager.java +++ b/src/test/java/org/traccar/TestIdentityManager.java @@ -29,10 +29,7 @@ public final class TestIdentityManager implements IdentityManager { return createDevice(); } - public String getDevicePassword(long id) { - return null; - } - + @Override public String getDevicePassword(long id, String defaultPassword) { return defaultPassword; } -- cgit v1.2.3 From 01cb6d0be635976128fade70a36a9726539bc401 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Thu, 11 Jul 2019 23:47:54 -0400 Subject: Changes after sixth review --- .../org/traccar/protocol/LaipacProtocolDecoder.java | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index c3b12aa80..e03ff672c 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -40,15 +40,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { public static final String DEFAULT_DEVICE_PASSWORD = "00000000"; - private static final Pattern PATTERN_ECHK = new PatternBuilder() - .text("$ECHK") - .expression(",([^,]+)") // identifier - .number(",(d+)") // sequence number - .text("*") - .number("(xx)") // checksum - .compile(); - - private static final Pattern PATTERN_AVRMC = new PatternBuilder() + private static final Pattern PATTERN = new PatternBuilder() .text("$AVRMC,") .expression("([^,]+),") // identifier .number("(dd)(dd)(dd),") // time (hhmmss) @@ -174,11 +166,6 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { private Object decodeEchk( String sentence, Channel channel, SocketAddress remoteAddress) { - Parser parser = new Parser(PATTERN_ECHK, sentence); - if (!parser.matches()) { - return null; - } - if (channel != null) { channel.writeAndFlush(new NetworkMessage(sentence + "\r\n", remoteAddress)); } @@ -189,7 +176,7 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { protected Object decodeAvrmc( String sentence, Channel channel, SocketAddress remoteAddress) { - Parser parser = new Parser(PATTERN_AVRMC, sentence); + Parser parser = new Parser(PATTERN, sentence); if (!parser.matches()) { return null; } -- cgit v1.2.3 From 4fd816d4fcd35b1ab59857c3662d592a23372d94 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Fri, 12 Jul 2019 08:53:31 -0400 Subject: Changes after seventh review --- .../org/traccar/protocol/LaipacProtocolDecoder.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index e03ff672c..7c73ee7be 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -163,16 +163,6 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { } - private Object decodeEchk( - String sentence, Channel channel, SocketAddress remoteAddress) { - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(sentence + "\r\n", remoteAddress)); - } - - return null; - } - protected Object decodeAvrmc( String sentence, Channel channel, SocketAddress remoteAddress) { @@ -246,9 +236,10 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { String sentence = (String) msg; if (sentence.startsWith("$ECHK")) { - return decodeEchk(sentence, channel, remoteAddress); - } - if (sentence.startsWith("$AVRMC")) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(sentence + "\r\n", remoteAddress)); + } + } else if (sentence.startsWith("$AVRMC")) { return decodeAvrmc(sentence, channel, remoteAddress); } -- cgit v1.2.3 From 1da58124acf0ce8c820b78519d17c2a408aced24 Mon Sep 17 00:00:00 2001 From: Edward Valley Date: Fri, 12 Jul 2019 13:26:48 -0400 Subject: Avoid directly handling ignition attribute --- src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index 7c73ee7be..2302015f5 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -99,17 +99,12 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { private String decodeEvent(String event, Position position) { - position.set(Position.KEY_IGNITION, false); - if (event.length() == 1) { char inputStatus = event.charAt(0); if (inputStatus >= 'A' && inputStatus <= 'D') { int inputStatusInt = inputStatus - 'A'; position.set(Position.PREFIX_IN + 1, inputStatusInt & 1); position.set(Position.PREFIX_IN + 2, inputStatusInt & 2); - if ((inputStatusInt & 1) != 0) { - position.set(Position.KEY_IGNITION, true); - } return null; } } -- cgit v1.2.3