Example usage for io.netty.buffer ByteBufUtil hexDump

List of usage examples for io.netty.buffer ByteBufUtil hexDump

Introduction

In this page you can find the example usage for io.netty.buffer ByteBufUtil hexDump.

Prototype

public static String hexDump(byte[] array) 

Source Link

Document

Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a> of the specified byte array.

Usage

From source file:org.traccar.protocol.TekProtocolDecoder.java

License:Apache License

@Override
protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {

    ByteBuf buf = (ByteBuf) msg;//from  w  ww . j  a va  2 s . c o m

    buf.readUnsignedByte(); // product type
    buf.readUnsignedByte(); // hardware version
    buf.readUnsignedByte(); // firmware version
    buf.readUnsignedByte(); // contact reason
    buf.readUnsignedByte(); // alarm / status
    buf.readUnsignedByte(); // rssi
    buf.readUnsignedByte(); // battery / status

    String imei = ByteBufUtil.hexDump(buf.readBytes(8)).substring(1);
    DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
    if (deviceSession == null) {
        return null;
    }

    int type = BitUtil.to(buf.readUnsignedByte(), 6);
    buf.readUnsignedByte(); // length

    if (type == 4 || type == 8) {

        Position position = new Position(getProtocolName());
        position.setDeviceId(deviceSession.getDeviceId());

        int count = buf.readUnsignedShort();
        buf.readUnsignedByte(); // hours / tickets
        buf.readUnsignedByte(); // error code
        buf.readUnsignedByte(); // reserved
        buf.readUnsignedByte(); // logger speed
        buf.readUnsignedByte(); // login time
        buf.readUnsignedByte(); // minutes

        for (int i = 0; i < count; i++) {
            position.set("rssi" + (i + 1), buf.readUnsignedByte());
            position.set("temp" + (i + 1), buf.readUnsignedByte() - 30);
            int data = buf.readUnsignedShort();
            position.set("src" + (i + 1), BitUtil.from(data, 10));
            position.set("ullage" + (i + 1), BitUtil.to(data, 10));
        }

        return position;

    } else if (type == 17) {

        String sentence = buf.toString(StandardCharsets.US_ASCII);

        Parser parser = new Parser(PATTERN, sentence);
        if (!parser.matches()) {
            return null;
        }

        Position position = new Position(getProtocolName());
        position.setDeviceId(deviceSession.getDeviceId());

        DateBuilder dateBuilder = new DateBuilder().setTime(parser.nextInt(), parser.nextInt(),
                parser.nextInt());

        position.setLatitude(parser.nextCoordinate());
        position.setLongitude(parser.nextCoordinate());

        position.set(Position.KEY_HDOP, parser.nextDouble());

        position.setAltitude(parser.nextDouble());
        position.setValid(parser.nextInt() > 0);
        position.setCourse(parser.nextDouble());
        position.setSpeed(parser.nextDouble());

        dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
        position.setTime(dateBuilder.getDate());

        return position;

    }

    return null;
}

From source file:org.traccar.protocol.TeltonikaProtocolDecoder.java

License:Apache License

private void decodeSerial(Channel channel, SocketAddress remoteAddress, Position position, ByteBuf buf) {

    getLastLocation(position, null);//  www  . j a  v a 2 s  .  c o m

    int type = buf.readUnsignedByte();
    if (type == 0x0D) {

        buf.readInt(); // length
        int subtype = buf.readUnsignedByte();
        if (subtype == 0x01) {

            long photoId = buf.readUnsignedInt();
            ByteBuf photo = Unpooled.buffer(buf.readInt());
            photos.put(photoId, photo);
            sendImageRequest(channel, remoteAddress, photoId, 0, Math.min(IMAGE_PACKET_MAX, photo.capacity()));

        } else if (subtype == 0x02) {

            long photoId = buf.readUnsignedInt();
            buf.readInt(); // offset
            ByteBuf photo = photos.get(photoId);
            photo.writeBytes(buf, buf.readUnsignedShort());
            if (photo.writableBytes() > 0) {
                sendImageRequest(channel, remoteAddress, photoId, photo.writerIndex(),
                        Math.min(IMAGE_PACKET_MAX, photo.writableBytes()));
            } else {
                String uniqueId = Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId();
                photos.remove(photoId);
                try {
                    position.set(Position.KEY_IMAGE,
                            Context.getMediaManager().writeFile(uniqueId, photo, "jpg"));
                } finally {
                    photo.release();
                }
            }

        }

    } else {

        position.set(Position.KEY_TYPE, type);

        int length = buf.readInt();
        boolean readable = true;
        for (int i = 0; i < length; i++) {
            byte b = buf.getByte(buf.readerIndex() + i);
            if (b < 32 && b != '\r' && b != '\n') {
                readable = false;
                break;
            }
        }

        if (readable) {
            position.set(Position.KEY_RESULT, buf.readSlice(length).toString(StandardCharsets.US_ASCII));
        } else {
            position.set(Position.KEY_RESULT, ByteBufUtil.hexDump(buf.readSlice(length)));
        }
    }
}

From source file:org.traccar.protocol.TeltonikaProtocolDecoder.java

License:Apache License

private void decodeLocation(Position position, ByteBuf buf, int codec) {

    int globalMask = 0x0f;

    if (codec == CODEC_GH3000) {

        long time = buf.readUnsignedInt() & 0x3fffffff;
        time += 1167609600; // 2007-01-01 00:00:00

        globalMask = buf.readUnsignedByte();
        if (BitUtil.check(globalMask, 0)) {

            position.setTime(new Date(time * 1000));

            int locationMask = buf.readUnsignedByte();

            if (BitUtil.check(locationMask, 0)) {
                position.setLatitude(buf.readFloat());
                position.setLongitude(buf.readFloat());
            }//from  w  w  w  .  j  a  va  2 s  . c o  m

            if (BitUtil.check(locationMask, 1)) {
                position.setAltitude(buf.readUnsignedShort());
            }

            if (BitUtil.check(locationMask, 2)) {
                position.setCourse(buf.readUnsignedByte() * 360.0 / 256);
            }

            if (BitUtil.check(locationMask, 3)) {
                position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
            }

            if (BitUtil.check(locationMask, 4)) {
                position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
            }

            if (BitUtil.check(locationMask, 5)) {
                CellTower cellTower = CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedShort());

                if (BitUtil.check(locationMask, 6)) {
                    cellTower.setSignalStrength((int) buf.readUnsignedByte());
                }

                if (BitUtil.check(locationMask, 7)) {
                    cellTower.setOperator(buf.readUnsignedInt());
                }

                position.setNetwork(new Network(cellTower));

            } else {
                if (BitUtil.check(locationMask, 6)) {
                    position.set(Position.KEY_RSSI, buf.readUnsignedByte());
                }
                if (BitUtil.check(locationMask, 7)) {
                    position.set(Position.KEY_OPERATOR, buf.readUnsignedInt());
                }
            }

        } else {

            getLastLocation(position, new Date(time * 1000));

        }

    } else {

        position.setTime(new Date(buf.readLong()));

        position.set("priority", buf.readUnsignedByte());

        position.setLongitude(buf.readInt() / 10000000.0);
        position.setLatitude(buf.readInt() / 10000000.0);
        position.setAltitude(buf.readShort());
        position.setCourse(buf.readUnsignedShort());

        int satellites = buf.readUnsignedByte();
        position.set(Position.KEY_SATELLITES, satellites);

        position.setValid(satellites != 0);

        position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort()));

        position.set(Position.KEY_EVENT, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16));
        if (codec == CODEC_16) {
            buf.readUnsignedByte(); // generation type
        }

        readExtByte(buf, codec, CODEC_8_EXT); // total IO data records

    }

    // Read 1 byte data
    if (BitUtil.check(globalMask, 1)) {
        int cnt = readExtByte(buf, codec, CODEC_8_EXT);
        for (int j = 0; j < cnt; j++) {
            decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 1, codec);
        }
    }

    // Read 2 byte data
    if (BitUtil.check(globalMask, 2)) {
        int cnt = readExtByte(buf, codec, CODEC_8_EXT);
        for (int j = 0; j < cnt; j++) {
            decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 2, codec);
        }
    }

    // Read 4 byte data
    if (BitUtil.check(globalMask, 3)) {
        int cnt = readExtByte(buf, codec, CODEC_8_EXT);
        for (int j = 0; j < cnt; j++) {
            decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 4, codec);
        }
    }

    // Read 8 byte data
    if (codec == CODEC_8 || codec == CODEC_8_EXT || codec == CODEC_16) {
        int cnt = readExtByte(buf, codec, CODEC_8_EXT);
        for (int j = 0; j < cnt; j++) {
            decodeOtherParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 8);
        }
    }

    // Read 16 byte data
    if (extended) {
        int cnt = readExtByte(buf, codec, CODEC_8_EXT);
        for (int j = 0; j < cnt; j++) {
            int id = readExtByte(buf, codec, CODEC_8_EXT, CODEC_16);
            position.set(Position.PREFIX_IO + id, ByteBufUtil.hexDump(buf.readSlice(16)));
        }
    }

    // Read X byte data
    if (codec == CODEC_8_EXT) {
        int cnt = buf.readUnsignedShort();
        for (int j = 0; j < cnt; j++) {
            int id = buf.readUnsignedShort();
            int length = buf.readUnsignedShort();
            if (id == 256) {
                position.set(Position.KEY_VIN, buf.readSlice(length).toString(StandardCharsets.US_ASCII));
            } else {
                position.set(Position.PREFIX_IO + id, ByteBufUtil.hexDump(buf.readSlice(length)));
            }
        }
    }

    decodeNetwork(position);

}

From source file:org.traccar.protocol.TytanProtocolDecoder.java

License:Apache License

private void decodeExtraData(Position position, ByteBuf buf, int end) {
    while (buf.readerIndex() < end) {

        int type = buf.readUnsignedByte();
        int length = buf.readUnsignedByte();
        if (length == 255) {
            length += buf.readUnsignedByte();
        }/*w w w  .  ja  va 2  s  .  c  o m*/

        int n;

        switch (type) {
        case 2:
            position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedMedium());
            break;
        case 5:
            position.set(Position.KEY_INPUT, buf.readUnsignedByte());
            break;
        case 6:
            n = buf.readUnsignedByte() >> 4;
            if (n < 2) {
                position.set(Position.PREFIX_ADC + n, buf.readFloat());
            } else {
                position.set("di" + (n - 2), buf.readFloat());
            }
            break;
        case 7:
            int alarm = buf.readUnsignedByte();
            buf.readUnsignedByte();
            if (BitUtil.check(alarm, 5)) {
                position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
            }
            break;
        case 8:
            position.set("antihijack", buf.readUnsignedByte());
            break;
        case 9:
            position.set("unauthorized", ByteBufUtil.hexDump(buf.readSlice(8)));
            break;
        case 10:
            position.set("authorized", ByteBufUtil.hexDump(buf.readSlice(8)));
            break;
        case 24:
            for (int i = 0; i < length / 2; i++) {
                position.set(Position.PREFIX_TEMP + buf.readUnsignedByte(), buf.readByte());
            }
            break;
        case 28:
            position.set(Position.KEY_AXLE_WEIGHT, buf.readUnsignedShort());
            buf.readUnsignedByte();
            break;
        case 90:
            position.set(Position.KEY_POWER, buf.readFloat());
            break;
        case 101:
            position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte());
            break;
        case 102:
            position.set(Position.KEY_RPM, buf.readUnsignedByte() * 50);
            break;
        case 107:
            int fuel = buf.readUnsignedShort();
            int fuelFormat = fuel >> 14;
            if (fuelFormat == 1) {
                position.set("fuelValue", (fuel & 0x3fff) * 0.4 + "%");
            } else if (fuelFormat == 2) {
                position.set("fuelValue", (fuel & 0x3fff) * 0.5 + " l");
            } else if (fuelFormat == 3) {
                position.set("fuelValue", (fuel & 0x3fff) * -0.5 + " l");
            }
            break;
        case 108:
            position.set(Position.KEY_OBD_ODOMETER, buf.readUnsignedInt() * 5);
            break;
        case 150:
            position.set(Position.KEY_DOOR, buf.readUnsignedByte());
            break;
        default:
            buf.skipBytes(length);
            break;
        }
    }
}

From source file:org.traccar.protocol.TzoneProtocolDecoder.java

License:Apache License

private void decodeCards(Position position, ByteBuf buf) {

    int index = 1;
    for (int i = 0; i < 4; i++) {

        int blockLength = buf.readUnsignedShort();
        int blockEnd = buf.readerIndex() + blockLength;

        if (blockLength > 0) {

            int count = buf.readUnsignedByte();
            for (int j = 0; j < count; j++) {

                int length = buf.readUnsignedByte();

                boolean odd = length % 2 != 0;
                if (odd) {
                    length += 1;/*from  w ww . ja  v  a  2 s .  c om*/
                }

                String num = ByteBufUtil.hexDump(buf.readSlice(length / 2));

                if (odd) {
                    num = num.substring(1);
                }

                position.set("card" + index, num);
            }
        }

        buf.readerIndex(blockEnd);
    }

}

From source file:org.traccar.protocol.TzoneProtocolDecoder.java

License:Apache License

@Override
protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {

    ByteBuf buf = (ByteBuf) msg;//from   ww w. j a  v  a 2 s .  c  om

    buf.skipBytes(2); // header
    buf.readUnsignedShort(); // length
    if (buf.readUnsignedShort() != 0x2424) {
        return null;
    }
    int hardware = buf.readUnsignedShort();
    long firmware = buf.readUnsignedInt();

    String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1);
    DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
    if (deviceSession == null) {
        return null;
    }

    Position position = new Position(getProtocolName());
    position.setDeviceId(deviceSession.getDeviceId());

    position.set(Position.KEY_VERSION_HW, hardware);
    position.set(Position.KEY_VERSION_FW, firmware);

    position.setDeviceTime(
            new DateBuilder().setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
                    .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()).getDate());

    // GPS info

    if (hardware == 0x406 || !decodeGps(position, buf, hardware)) {

        getLastLocation(position, position.getDeviceTime());

    }

    // LBS info

    int blockLength = buf.readUnsignedShort();
    int blockEnd = buf.readerIndex() + blockLength;

    if (blockLength > 0 && (hardware == 0x10A || hardware == 0x10B || hardware == 0x406)) {
        position.setNetwork(
                new Network(CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedShort())));
    }

    buf.readerIndex(blockEnd);

    // Status info

    blockLength = buf.readUnsignedShort();
    blockEnd = buf.readerIndex() + blockLength;

    if (blockLength >= 13) {
        position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
        position.set("terminalInfo", buf.readUnsignedByte());

        int status = buf.readUnsignedByte();
        position.set(Position.PREFIX_OUT + 1, BitUtil.check(status, 0));
        position.set(Position.PREFIX_OUT + 2, BitUtil.check(status, 1));
        status = buf.readUnsignedByte();
        position.set(Position.PREFIX_IN + 1, BitUtil.check(status, 4));
        if (BitUtil.check(status, 0)) {
            position.set(Position.KEY_ALARM, Position.ALARM_SOS);
        }

        position.set(Position.KEY_RSSI, buf.readUnsignedByte());
        position.set("gsmStatus", buf.readUnsignedByte());
        position.set(Position.KEY_BATTERY, buf.readUnsignedShort());
        position.set(Position.KEY_POWER, buf.readUnsignedShort());
        position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort());
        position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort());
    }

    if (blockLength >= 15) {
        position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort());
    }

    buf.readerIndex(blockEnd);

    if (hardware == 0x10B) {

        decodeCards(position, buf);

        buf.skipBytes(buf.readUnsignedShort()); // temperature
        buf.skipBytes(buf.readUnsignedShort()); // lock

        decodePassengers(position, buf);

    }

    if (hardware == 0x406) {

        decodeTags(position, buf);

    }

    return position;
}

From source file:org.traccar.protocol.UlbotechProtocolDecoder.java

License:Apache License

private void decodeObd(Position position, ByteBuf buf, int length) {

    int end = buf.readerIndex() + length;

    while (buf.readerIndex() < end) {
        int parameterLength = buf.getUnsignedByte(buf.readerIndex()) >> 4;
        int mode = buf.readUnsignedByte() & 0x0F;
        position.add(ObdDecoder.decode(mode, ByteBufUtil.hexDump(buf.readSlice(parameterLength - 1))));
    }/*w  w w  .ja  v  a  2s .c  o  m*/
}

From source file:org.traccar.protocol.UlbotechProtocolDecoder.java

License:Apache License

private void decodeJ1708(Position position, ByteBuf buf, int length) {

    int end = buf.readerIndex() + length;

    while (buf.readerIndex() < end) {
        int mark = buf.readUnsignedByte();
        int len = BitUtil.between(mark, 0, 6);
        int type = BitUtil.between(mark, 6, 8);
        int id = buf.readUnsignedByte();
        if (type == 3) {
            id += 256;/*from   www.  jav  a 2s . c  o  m*/
        }
        String value = ByteBufUtil.hexDump(buf.readSlice(len - 1));
        if (type == 2 || type == 3) {
            position.set("pid" + id, value);
        }
    }
}

From source file:org.traccar.protocol.UlbotechProtocolDecoder.java

License:Apache License

private Object decodeBinary(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {

    buf.readUnsignedByte(); // header
    buf.readUnsignedByte(); // version
    buf.readUnsignedByte(); // type

    String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1);

    DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
    if (deviceSession == null) {
        return null;
    }// w  w  w.  ja v  a2 s  .c  om

    if (deviceSession.getTimeZone() == null) {
        deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId()));
    }

    Position position = new Position(getProtocolName());
    position.setDeviceId(deviceSession.getDeviceId());

    long seconds = buf.readUnsignedInt() & 0x7fffffffL;
    seconds += 946684800L; // 2000-01-01 00:00
    seconds -= deviceSession.getTimeZone().getRawOffset() / 1000;
    Date time = new Date(seconds * 1000);

    boolean hasLocation = false;

    while (buf.readableBytes() > 3) {

        int type = buf.readUnsignedByte();
        int length = type == DATA_CANBUS ? buf.readUnsignedShort() : buf.readUnsignedByte();

        switch (type) {

        case DATA_GPS:
            hasLocation = true;
            position.setValid(true);
            position.setLatitude(buf.readInt() / 1000000.0);
            position.setLongitude(buf.readInt() / 1000000.0);
            position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort()));
            position.setCourse(buf.readUnsignedShort());
            position.set(Position.KEY_HDOP, buf.readUnsignedShort());
            break;

        case DATA_LBS:
            if (length == 11) {
                position.setNetwork(new Network(CellTower.from(buf.readUnsignedShort(), buf.readUnsignedShort(),
                        buf.readUnsignedShort(), buf.readUnsignedInt(), -buf.readUnsignedByte())));
            } else {
                position.setNetwork(new Network(CellTower.from(buf.readUnsignedShort(), buf.readUnsignedShort(),
                        buf.readUnsignedShort(), buf.readUnsignedShort(), -buf.readUnsignedByte())));
            }
            if (length > 9 && length != 11) {
                buf.skipBytes(length - 9);
            }
            break;

        case DATA_STATUS:
            int status = buf.readUnsignedShort();
            position.set(Position.KEY_IGNITION, BitUtil.check(status, 9));
            position.set(Position.KEY_STATUS, status);
            position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedShort()));
            break;

        case DATA_ODOMETER:
            position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
            break;

        case DATA_ADC:
            decodeAdc(position, buf, length);
            break;

        case DATA_GEOFENCE:
            position.set("geofenceIn", buf.readUnsignedInt());
            position.set("geofenceAlarm", buf.readUnsignedInt());
            break;

        case DATA_OBD2:
            decodeObd(position, buf, length);
            break;

        case DATA_FUEL:
            position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt() / 10000.0);
            break;

        case DATA_OBD2_ALARM:
            decodeObd(position, buf, length);
            break;

        case DATA_HARSH_DRIVER:
            decodeDriverBehavior(position, buf);
            break;

        case DATA_CANBUS:
            position.set("can", ByteBufUtil.hexDump(buf.readSlice(length)));
            break;

        case DATA_J1708:
            decodeJ1708(position, buf, length);
            break;

        case DATA_VIN:
            position.set(Position.KEY_VIN, buf.readSlice(length).toString(StandardCharsets.US_ASCII));
            break;

        case DATA_RFID:
            position.set(Position.KEY_DRIVER_UNIQUE_ID,
                    buf.readSlice(length - 1).toString(StandardCharsets.US_ASCII));
            position.set("authorized", buf.readUnsignedByte() != 0);
            break;

        case DATA_EVENT:
            position.set(Position.KEY_EVENT, buf.readUnsignedByte());
            if (length > 1) {
                position.set("eventMask", buf.readUnsignedInt());
            }
            break;

        default:
            buf.skipBytes(length);
            break;
        }
    }

    if (!hasLocation) {
        getLastLocation(position, time);
    } else {
        position.setTime(time);
    }

    return position;
}

From source file:org.traccar.protocol.UproProtocolDecoder.java

License:Apache License

@Override
protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {

    ByteBuf buf = (ByteBuf) msg;/*  w  ww.  ja  v a2 s.  c om*/

    if (buf.getByte(buf.readerIndex()) != '*') {
        return null;
    }

    int headerIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '&');
    if (headerIndex < 0) {
        headerIndex = buf.writerIndex();
    }
    String header = buf.readSlice(headerIndex - buf.readerIndex()).toString(StandardCharsets.US_ASCII);

    Parser parser = new Parser(PATTERN_HEADER, header);
    if (!parser.matches()) {
        return null;
    }

    String head = parser.next();
    boolean reply = parser.next().equals("1");

    DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
    if (deviceSession == null) {
        return null;
    }

    Position position = new Position(getProtocolName());
    position.setDeviceId(deviceSession.getDeviceId());

    String type = parser.next();
    String subtype = parser.next();

    if (reply && channel != null) {
        channel.writeAndFlush(new NetworkMessage("*" + head + "Y" + type + subtype + "#", remoteAddress));
    }

    while (buf.isReadable()) {

        buf.readByte(); // skip delimiter

        byte dataType = buf.readByte();

        int delimiterIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '&');
        if (delimiterIndex < 0) {
            delimiterIndex = buf.writerIndex();
        }

        ByteBuf data = buf.readSlice(delimiterIndex - buf.readerIndex());

        switch (dataType) {
        case 'A':
            decodeLocation(position, data.toString(StandardCharsets.US_ASCII));
            break;
        case 'B':
            position.set(Position.KEY_STATUS, data.toString(StandardCharsets.US_ASCII));
            break;
        case 'C':
            long odometer = 0;
            while (data.isReadable()) {
                odometer <<= 4;
                odometer += data.readByte() - (byte) '0';
            }
            position.set(Position.KEY_ODOMETER, odometer * 2 * 1852 / 3600);
            break;
        case 'F':
            position.setSpeed(Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)) * 0.1);
            break;
        case 'K':
            position.set("statusExtended", data.toString(StandardCharsets.US_ASCII));
            break;
        case 'P':
            if (data.readableBytes() >= 16) {
                position.setNetwork(new Network(
                        CellTower.from(Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)),
                                Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)),
                                Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII), 16),
                                Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII), 16))));
            }
            break;
        case 'Q':
            position.set("obdPid", ByteBufUtil.hexDump(data));
            break;
        case 'R':
            if (head.startsWith("HQ")) {
                position.set(Position.KEY_RSSI,
                        Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII)));
                position.set(Position.KEY_SATELLITES,
                        Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII)));
            } else {
                position.set("odbTravel", ByteBufUtil.hexDump(data));
            }
            break;
        case 'S':
            position.set("obdTraffic", ByteBufUtil.hexDump(data));
            break;
        case 'T':
            position.set(Position.KEY_BATTERY_LEVEL,
                    Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII)));
            break;
        case 'V':
            position.set(Position.KEY_POWER,
                    Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)) * 0.1);
            break;
        default:
            break;
        }

    }

    if (position.getLatitude() != 0 && position.getLongitude() != 0) {
        return position;
    }

    return null;
}