From 4d01f322be1c49f7a057bda6e9ce7e492b9b7311 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 17 May 2014 21:05:31 +1200 Subject: Implement T322 protocol (fix #499) --- src/org/traccar/ServerManager.java | 12 +-- src/org/traccar/protocol/MeitrackFrameDecoder.java | 49 +++++++++ .../traccar/protocol/MeitrackProtocolDecoder.java | 110 +++++++++++++++++++-- 3 files changed, 158 insertions(+), 13 deletions(-) create mode 100644 src/org/traccar/protocol/MeitrackFrameDecoder.java (limited to 'src') diff --git a/src/org/traccar/ServerManager.java b/src/org/traccar/ServerManager.java index 1a3cf0a00..6d65dad18 100644 --- a/src/org/traccar/ServerManager.java +++ b/src/org/traccar/ServerManager.java @@ -519,17 +519,15 @@ public class ServerManager { private void initMeitrackServer(String protocol) throws SQLException { if (isProtocolEnabled(properties, protocol)) { - serverList.add(new TrackerServer(this, new ServerBootstrap(), protocol) { + TrackerServer server = new TrackerServer(this, new ServerBootstrap(), protocol) { @Override protected void addSpecificHandlers(ChannelPipeline pipeline) { - byte delimiter[] = { (byte) '\r', (byte) '\n' }; - pipeline.addLast("frameDecoder", - new DelimiterBasedFrameDecoder(1024, ChannelBuffers.wrappedBuffer(delimiter))); - pipeline.addLast("stringDecoder", new StringDecoder()); - pipeline.addLast("stringEncoder", new StringEncoder()); + pipeline.addLast("frameDecoder", new MeitrackFrameDecoder()); pipeline.addLast("objectDecoder", new MeitrackProtocolDecoder(ServerManager.this)); } - }); + }; + server.setEndianness(ByteOrder.LITTLE_ENDIAN); + serverList.add(server); } } diff --git a/src/org/traccar/protocol/MeitrackFrameDecoder.java b/src/org/traccar/protocol/MeitrackFrameDecoder.java new file mode 100644 index 000000000..f7dda10e2 --- /dev/null +++ b/src/org/traccar/protocol/MeitrackFrameDecoder.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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 java.nio.charset.Charset; +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.handler.codec.frame.FrameDecoder; +import org.traccar.helper.ChannelBufferTools; + +public class MeitrackFrameDecoder extends FrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, + Channel channel, + ChannelBuffer buf) throws Exception { + + if (buf.readableBytes() < 10) { + return null; + } + + Integer index = ChannelBufferTools.find(buf, 0, buf.readableBytes(), ","); + if (index != null) + { + int length = index + Integer.valueOf(buf.toString(3, index - 3, Charset.defaultCharset())); + if (buf.readableBytes() >= length) { + return buf.readBytes(length); + } + } + + return null; + } + +} diff --git a/src/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/org/traccar/protocol/MeitrackProtocolDecoder.java index e2f31b207..ab12d510b 100644 --- a/src/org/traccar/protocol/MeitrackProtocolDecoder.java +++ b/src/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -15,14 +15,20 @@ */ package org.traccar.protocol; +import java.nio.charset.Charset; import java.util.Calendar; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.traccar.BaseProtocolDecoder; import org.traccar.ServerManager; +import org.traccar.helper.ChannelBufferTools; import org.traccar.helper.Log; import org.traccar.model.ExtendedInfoFormatter; import org.traccar.model.Position; @@ -61,13 +67,10 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { "(\\p{XDigit}+)," + // Power ".*"); // TODO: parse other stuff - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, Object msg) - throws Exception { + private Position decodeRegularMessage(ChannelBuffer buf) { // Parse message - String sentence = (String) msg; + String sentence = buf.toString(Charset.defaultCharset()); Matcher parser = pattern.matcher(sentence); if (!parser.matches()) { return null; @@ -79,7 +82,7 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { Integer index = 1; - // Get device by IMEI + // Identification String imei = parser.group(index++); try { position.setDeviceId(getDataManager().getDeviceByImei(imei).getId()); @@ -149,4 +152,99 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder { return position; } + private List decodeBinaryMessage(ChannelBuffer buf) { + List positions = new LinkedList(); + + Integer index = ChannelBufferTools.find(buf, 0, buf.readableBytes(), ","); + + // Identification + long deviceId; + String imei = buf.toString(index + 1, 15, Charset.defaultCharset()); + try { + deviceId = getDataManager().getDeviceByImei(imei).getId(); + } catch(Exception error) { + Log.warning("Unknown device - " + imei); + return null; + } + + buf.skipBytes(index + 1 + 15 + 1 + 3 + 1 + 2 + 2 + 4); + + while (buf.readableBytes() >= 0x34) { + + Position position = new Position(); + ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter("meitrack"); + position.setDeviceId(deviceId); + + // Event + extendedInfo.set("event", buf.readUnsignedByte()); + + // Location + position.setLatitude(buf.readInt() * 0.000001); + position.setLongitude(buf.readInt() * 0.000001); + + // Time (946684800 - timestamp for 2000-01-01) + position.setTime(new Date((946684800 + buf.readUnsignedInt()) * 1000)); + + // Validity + position.setValid(buf.readUnsignedByte() == 1); + + // Satellites + extendedInfo.set("satellites", buf.readUnsignedByte()); + + // GSM Signal + extendedInfo.set("gsm", buf.readUnsignedByte()); + + // Speed + position.setSpeed(buf.readUnsignedShort() * 0.539957); + + // Course + position.setCourse((double) buf.readUnsignedShort()); + + // HDOP + extendedInfo.set("hdop", buf.readUnsignedShort() * 0.1); + + // Altitude + position.setAltitude((double) buf.readUnsignedShort()); + + // Other + extendedInfo.set("milage", buf.readUnsignedInt()); + extendedInfo.set("runtime", buf.readUnsignedInt()); + extendedInfo.set("cell", + buf.readUnsignedShort() + "|" + buf.readUnsignedShort() + "|" + + buf.readUnsignedShort() + "|" + buf.readUnsignedShort()); + extendedInfo.set("state", buf.readUnsignedShort()); + + // ADC + extendedInfo.set("adc1", buf.readUnsignedShort()); + extendedInfo.set("battery", buf.readUnsignedShort() * 0.01); + extendedInfo.set("power", buf.readUnsignedShort()); + + buf.readUnsignedInt(); // geo-fence + + position.setExtendedInfo(extendedInfo.toString()); + positions.add(position); + } + + return positions; + } + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, Object msg) + throws Exception { + + ChannelBuffer buf = (ChannelBuffer) msg; + + // Find type + Integer index = ChannelBufferTools.find(buf, 0, buf.readableBytes(), ","); + index = ChannelBufferTools.find(buf, index + 1, buf.readableBytes(), ","); + + String type = buf.toString(index + 1, 3, Charset.defaultCharset()); + if (type.equals("CCC")) { + return decodeBinaryMessage(buf); + } else { + return decodeRegularMessage(buf); + } + } + } -- cgit v1.2.3