From d5589821cd437fcce5f12e82a6dfe05f57262542 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 25 Mar 2015 18:31:39 +1300 Subject: Implement BCE protocol (fix #805) --- src/org/traccar/protocol/BceProtocolDecoder.java | 164 ++++++++++++++--------- 1 file changed, 103 insertions(+), 61 deletions(-) (limited to 'src/org/traccar/protocol/BceProtocolDecoder.java') diff --git a/src/org/traccar/protocol/BceProtocolDecoder.java b/src/org/traccar/protocol/BceProtocolDecoder.java index d07be6ef4..a1c45758c 100644 --- a/src/org/traccar/protocol/BceProtocolDecoder.java +++ b/src/org/traccar/protocol/BceProtocolDecoder.java @@ -15,15 +15,16 @@ */ package org.traccar.protocol; -import java.util.Calendar; +import java.nio.ByteOrder; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; import java.util.Properties; -import java.util.TimeZone; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; - import org.traccar.BaseProtocolDecoder; import org.traccar.database.DataManager; import org.traccar.helper.Log; @@ -36,12 +37,18 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { super(dataManager, protocol, properties); } + private static final int DATA_TYPE = 7; + private static final int MSG_ASYNC_STACK = 0xA5; private static final int MSG_STACK_COFIRM = 0x19; private static final int MSG_TIME_TRIGGERED = 0xA0; private static final int MSG_OUTPUT_CONTROL = 0x41; private static final int MSG_OUTPUT_CONTROL_ACK = 0xC1; + private static boolean checkBit(int mask, int bit) { + return (mask & (1 << bit)) != 0; + } + @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, Object msg) @@ -50,81 +57,116 @@ public class BceProtocolDecoder extends BaseProtocolDecoder { ChannelBuffer buf = (ChannelBuffer) msg; String imei = String.format("%015d", buf.readLong()); - + long deviceId; + try { + deviceId = getDataManager().getDeviceByImei(imei).getId(); + } catch (Exception error) { + Log.warning("Unknown device - " + imei); + return null; + } - /*buf.skipBytes(2); // header - buf.readByte(); // size + List positions = new LinkedList(); - // Zero for location messages - buf.readByte(); // voltage - buf.readByte(); // gsm signal + while (buf.readableBytes() > 1) { - String imei = readImei(buf); - long index = buf.readUnsignedShort(); - int type = buf.readUnsignedByte(); + int dataEnd = buf.readUnsignedShort() + buf.readerIndex(); + int type = buf.readUnsignedByte(); + int confirmKey = buf.readUnsignedByte(); - if (type == MSG_HEARTBEAT) { - if (channel != null) { - byte[] response = {0x54, 0x68, 0x1A, 0x0D, 0x0A}; - channel.write(ChannelBuffers.wrappedBuffer(response)); - } - } + while (buf.readerIndex() < dataEnd) { - else if (type == MSG_DATA) { + Position position = new Position(); + ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter(getProtocol()); + position.setDeviceId(deviceId); - // Create new position - Position position = new Position(); - ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter(getProtocol()); - extendedInfo.set("index", index); + int structEnd = buf.readUnsignedByte() + buf.readerIndex(); - // Get device id - try { - position.setDeviceId(getDataManager().getDeviceByImei(imei).getId()); - } catch(Exception error) { - Log.warning("Unknown device - " + imei); - return null; - } + long time = buf.readUnsignedInt(); + if ((time & 0x0f) == DATA_TYPE) { - // Date and time - Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - time.clear(); - time.set(Calendar.YEAR, 2000 + buf.readUnsignedByte()); - time.set(Calendar.MONTH, buf.readUnsignedByte() - 1); - time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte()); - time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte()); - time.set(Calendar.MINUTE, buf.readUnsignedByte()); - time.set(Calendar.SECOND, buf.readUnsignedByte()); - position.setTime(time.getTime()); + time = time >> 4 << 1; + time += 0x47798280; // 01/01/2008 + position.setTime(new Date(time * 1000)); - // Latitude - double latitude = buf.readUnsignedInt() / (60.0 * 30000.0); + // Read masks + int mask; + List masks = new LinkedList(); + do { + mask = buf.readUnsignedShort(); + masks.add(mask); + } while (checkBit(mask, 15)); - // Longitude - double longitude = buf.readUnsignedInt() / (60.0 * 30000.0); + mask = masks.get(0); - // Speed - position.setSpeed((double) buf.readUnsignedByte()); + if (checkBit(mask, 0)) { + position.setValid(true); + position.setLongitude((double) buf.readFloat()); + position.setLatitude((double) buf.readFloat()); + position.setSpeed((double) buf.readUnsignedByte()); - // Course - position.setCourse((double) buf.readUnsignedShort()); + int gps = buf.readUnsignedByte(); + extendedInfo.set("satellites", gps & 0xf); + extendedInfo.set("hdop", gps >> 4); - buf.skipBytes(3); // reserved + position.setCourse((double) buf.readUnsignedByte()); + position.setAltitude((double) buf.readUnsignedShort()); - // Flags - long flags = buf.readUnsignedInt(); - position.setValid((flags & 0x1) == 0x1); - if ((flags & 0x2) == 0) latitude = -latitude; - if ((flags & 0x4) == 0) longitude = -longitude; + extendedInfo.set("milage", buf.readUnsignedInt()); - position.setLatitude(latitude); - position.setLongitude(longitude); - position.setAltitude(0.0); + position.setExtendedInfo(extendedInfo.toString()); + } - position.setExtendedInfo(extendedInfo.toString()); - return position; - }*/ + if (checkBit(mask, 1)) { + extendedInfo.set("input", buf.readUnsignedShort()); + } + + for (int i = 1; i <= 8; i++) { + if (checkBit(mask, i + 1)) { + extendedInfo.set("adc" + i, buf.readUnsignedShort()); + } + } + + if (checkBit(mask, 10)) buf.skipBytes(4); + if (checkBit(mask, 11)) buf.skipBytes(4); + if (checkBit(mask, 12)) buf.skipBytes(2); + if (checkBit(mask, 13)) buf.skipBytes(2); + + if (checkBit(mask, 14)) { + extendedInfo.set("mcc", buf.readUnsignedShort()); + extendedInfo.set("mnc", buf.readUnsignedByte()); + extendedInfo.set("lac", buf.readUnsignedShort()); + extendedInfo.set("cell", buf.readUnsignedShort()); + extendedInfo.set("gsm", buf.readUnsignedByte()); + buf.readUnsignedByte(); + } + + if (position.getValid() != null) { + positions.add(position); + } + } + + buf.readerIndex(structEnd); + } + + // Send response + if (type == MSG_ASYNC_STACK && channel != null) { + ChannelBuffer response = ChannelBuffers.buffer(ByteOrder.LITTLE_ENDIAN, 8 + 2 + 2 + 1); + response.writeLong(Long.valueOf(imei)); + response.writeShort(2); + response.writeByte(MSG_STACK_COFIRM); + response.writeByte(confirmKey); + + int checksum = 0; + for (int i = 0; i < response.writerIndex(); i++) { + checksum += response.getUnsignedByte(i); + } + response.writeByte(checksum); + + channel.write(response); + } + } - return null; + return positions; } } -- cgit v1.2.3