/*
* Copyright 2012 - 2017 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.jboss.netty.channel.socket.DatagramChannel;
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.Date;
import java.util.regex.Pattern;
public class T55ProtocolDecoder extends BaseProtocolDecoder {
public T55ProtocolDecoder(T55Protocol protocol) {
super(protocol);
}
private static final Pattern PATTERN_GPRMC = new PatternBuilder()
.text("$GPRMC,")
.number("(dd)(dd)(dd).?d*,") // time (hhmmss)
.expression("([AV]),") // validity
.number("(dd)(dd.d+),") // latitude
.expression("([NS]),")
.number("(d{2,3})(dd.d+),") // longitude
.expression("([EW]),")
.number("(d+.?d*)?,") // speed
.number("(d+.?d*)?,") // course
.number("(dd)(dd)(dd),") // date (ddmmyy)
.expression("[^*]+")
.text("*")
.expression("[^,]+")
.number(",(d+)") // satellites
.number(",(d+)") // imei
.expression(",([01])") // ignition
.number(",(d+)") // fuel
.number(",(d+)").optional(5) // battery
.number("((?:,d+)+)?") // parameters
.any()
.compile();
private static final Pattern PATTERN_GPGGA = new PatternBuilder()
.text("$GPGGA,")
.number("(dd)(dd)(dd).?d*,") // time (hhmmss)
.number("(d+)(dd.d+),") // latitude
.expression("([NS]),")
.number("(d+)(dd.d+),") // longitude
.expression("([EW]),")
.any()
.compile();
private static final Pattern PATTERN_GPRMA = new PatternBuilder()
.text("$GPRMA,")
.expression("([AV]),") // validity
.number("(dd)(dd.d+),") // latitude
.expression("([NS]),")
.number("(ddd)(dd.d+),") // longitude
.expression("([EW]),,,")
.number("(d+.?d*)?,") // speed
.number("(d+.?d*)?,") // course
.any()
.compile();
private static final Pattern PATTERN_TRCCR = new PatternBuilder()
.text("$TRCCR,")
.number("(dddd)(dd)(dd)") // date (yyyymmdd)
.number("(dd)(dd)(dd).?d*,") // time (hhmmss)
.expression("([AV]),") // validity
.number("(-?d+.d+),") // latitude
.number("(-?d+.d+),") // longitude
.number("(d+.d+),") // speed
.number("(d+.d+),") // course
.number("(-?d+.d+),") // altitude
.number("(d+.?d*),") // battery
.any()
.compile();
private Position position = null;
private Position decodeGprmc(
DeviceSession deviceSession, String sentence, SocketAddress remoteAddress, Channel channel) {
if (channel != null && !(channel instanceof DatagramChannel)) {
channel.write("OK1\r\n");
}
Parser parser = new Parser(PATTERN_GPRMC, sentence);
if (!parser.matches()) {
return null;
}
Position position = new Position();
position.setProtocol(getProtocolName());
if (deviceSession != null) {
position.setDeviceId(deviceSession.getDeviceId());
}
DateBuilder dateBuilder = new DateBuilder()
.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
position.setValid(parser.next().equals("A"));
position.setLatitude(parser.nextCoordinate());
position.setLongitude(parser.nextCoordinate());
position.setSpeed(parser.nextDouble(0));
position.setCourse(parser.nextDouble(0));
dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
position.setTime(dateBuilder.getDate());
if (parser.hasNext(5)) {
position.set(Position.KEY_SATELLITES, parser.next());
deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
if (deviceSession == null) {
return null;
}
position.setDeviceId(deviceSession.getDeviceId());
position.set(Position.KEY_IGNITION, parser.hasNext() && parser.next().equals("1"));
position.set(Position.KEY_FUEL_LEVEL, parser.nextInt(0));
position.set(Position.KEY_BATTERY, parser.nextInt());
}
if (parser.hasNext()) {
String[] parameters = parser.next().split(",");
for (int i = 1; i < parameters.length; i++) {
position.set(Position.PREFIX_IO + i, parameters[i]);
}
}
if (deviceSession != null) {
return position;
} else {
this.position = position; // save position
return null;
}
}
private Position decodeGpgga(DeviceSession deviceSession, String sentence) {
Parser parser = new Parser(PATTERN_GPGGA, sentence);
if (!parser.matches()) {
return null;
}
Position position = new Position();
position.setProtocol(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
DateBuilder dateBuilder = new DateBuilder()
.setCurrentDate()
.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
position.setTime(dateBuilder.getDate());
position.setValid(true);
position.setLatitude(parser.nextCoordinate());
position.setLongitude(parser.nextCoordinate());
return position;
}
private Position decodeGprma(DeviceSession deviceSession, String sentence) {
Parser parser = new Parser(PATTERN_GPRMA, sentence);
if (!parser.matches()) {
return null;
}
Position position = new Position();
position.setProtocol(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
position.setTime(new Date());
position.setValid(parser.next().equals("A"));
position.setLatitude(parser.nextCoordinate());
position.setLongitude(parser.nextCoordinate());
position.setSpeed(parser.nextDouble(0));
position.setCourse(parser.nextDouble(0));
return position;
}
private Position decodeTrccr(DeviceSession deviceSession, String sentence) {
Parser parser = new Parser(PATTERN_TRCCR, sentence);
if (!parser.matches()) {
return null;
}
Position position = new Position();
position.setProtocol(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
position.setTime(parser.nextDateTime());
position.setValid(parser.next().equals("A"));
position.setLatitude(parser.nextDouble(0));
position.setLongitude(parser.nextDouble(0));
position.setSpeed(parser.nextDouble(0));
position.setCourse(parser.nextDouble(0));
position.setAltitude(parser.nextDouble(0));
position.set(Position.KEY_BATTERY, parser.nextDouble(0));
return position;
}
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
DeviceSession deviceSession;
if (!sentence.startsWith("$") && sentence.contains("$")) {
int index = sentence.indexOf("$");
String id = sentence.substring(0, index);
if (id.endsWith(",")) {
id = id.substring(0, id.length() - 1);
} else if (id.endsWith("/")) {
id = id.substring(id.indexOf('/') + 1, id.length() - 1);
}
deviceSession = getDeviceSession(channel, remoteAddress, id);
sentence = sentence.substring(index);
} else {
deviceSession = getDeviceSession(channel, remoteAddress);
}
if (sentence.startsWith("$PGID")) {
getDeviceSession(channel, remoteAddress, sentence.substring(6, sentence.length() - 3));
} 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()));
} else if (sentence.startsWith("$GPFID")) {
deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(7, sentence.length()));
if (deviceSession != null && position != null) {
Position position = this.position;
position.setDeviceId(deviceSession.getDeviceId());
this.position = null;
return position;
}
} else if (sentence.matches("^[0-9A-F]+$")) {
getDeviceSession(channel, remoteAddress, sentence);
} else if (sentence.startsWith("$GPRMC")) {
return decodeGprmc(deviceSession, sentence, remoteAddress, channel);
} else if (sentence.startsWith("$GPGGA") && deviceSession != null) {
return decodeGpgga(deviceSession, sentence);
} else if (sentence.startsWith("$GPRMA") && deviceSession != null) {
return decodeGprma(deviceSession, sentence);
} else if (sentence.startsWith("$TRCCR") && deviceSession != null) {
return decodeTrccr(deviceSession, sentence);
}
return null;
}
}