Exemple #1
0
 /**
  * Decode a message header from a Netty buffer
  *
  * @param buffer The buffer to decode from
  * @param sender The sender of the packet, which has been set in the socket class
  * @return The partial message, only the header fields are filled
  */
 public static Message decodeHeader(
     final ChannelBuffer buffer, final InetSocketAddress recipient, final InetSocketAddress sender)
     throws DecoderException {
   final Message message = new Message();
   message.setVersion(buffer.readInt());
   message.setMessageId(buffer.readInt());
   //
   final int typeCommand = buffer.readUnsignedByte();
   message.setType(Type.values()[typeCommand >>> 4]);
   message.setCommand(Command.values()[typeCommand & 0xf]);
   final Number160 senderID = readID(buffer);
   final int portTCP = buffer.readUnsignedShort();
   final int portUDP = buffer.readUnsignedShort();
   final Number160 recipientID = readID(buffer);
   message.setRecipient(new PeerAddress(recipientID, recipient));
   final int contentType = buffer.readUnsignedShort();
   message.setContentType(
       Content.values()[contentType & 0xf],
       Content.values()[(contentType >>> 4) & 0xf],
       Content.values()[(contentType >>> 8) & 0xf],
       Content.values()[contentType >>> 12]);
   // set the address as we see it, important for port forwarding
   // identification
   final int senderMessageOptions = buffer.readUnsignedByte();
   final int senderOptions = senderMessageOptions >>> 4;
   final PeerAddress peerAddress =
       new PeerAddress(senderID, sender.getAddress(), portTCP, portUDP, senderOptions);
   message.setSender(peerAddress);
   final int options = senderMessageOptions & 0xf;
   message.setOptions(options);
   return message;
 }
 @Override
 public WindowClickMessage decode(ChannelBuffer buffer) throws IOException {
   int id = buffer.readUnsignedByte();
   int slot = buffer.readUnsignedShort();
   boolean rightClick = buffer.readUnsignedByte() != 0;
   int transaction = buffer.readUnsignedShort();
   boolean shift = buffer.readUnsignedByte() != 0;
   ItemStack item = ChannelBufferUtils.readItemStack(buffer);
   return new WindowClickMessage(id, slot, rightClick, transaction, shift, item);
 }
 @Override
 protected Object decode(
     ChannelHandlerContext chtx, Channel chan, ChannelBuffer in, AuthenticationStage state)
     throws Exception {
   switch (state) {
     case VALIDATION:
       int bytesLeft = readableBytes(in);
       if (bytesLeft >= 3) {
         int type = in.readUnsignedByte();
         int size = in.readUnsignedShort();
         if (size != readableBytes(in)) {
           throw new Exception("Mismatched login packet size.");
         }
         int version = in.readInt();
         if (version != 614) {
           throw new Exception("Incorrect revision read");
         }
         if (type == 16 || type == 18) {
           checkpoint(AuthenticationStage.DETAILS);
         }
       }
       break;
     case DETAILS:
       in.readUnsignedByte();
       int mode = in.readUnsignedByte();
       in.readUnsignedShort();
       in.readUnsignedShort();
       in.readUnsignedByte();
       in.skipBytes(24);
       readRS2String(in); // macaddress!
       in.readInt();
       int size = in.readUnsignedByte();
       in.skipBytes(size);
       in.skipBytes(6 + (33 * 4) + 8 + 2 + 14);
       if (in.readUnsignedByte() != 10) {
         throw new Exception("Invalid RSA header.");
       }
       in.readLong();
       in.readLong();
       long l = in.readLong();
       String name = longToString(l);
       String password = readRS2String(in);
       int left = readableBytes(in);
       in.skipBytes(left);
       return new LoginRequest(chan, chtx, name, password, mode);
   }
   return null;
 }
 private void decodeEventData(int event, ChannelBuffer buf) {
   switch (event) {
     case 2:
     case 40:
       buf.readUnsignedByte();
       break;
     case 9:
       buf.readUnsignedMedium();
       break;
     case 31:
     case 32:
       buf.readUnsignedShort();
       break;
     case 38:
       buf.skipBytes(4 * 9);
       break;
     case 113:
       buf.readUnsignedInt();
       buf.readUnsignedByte();
       break;
     case 121:
     case 142:
       buf.readLong();
       break;
     case 130:
       buf.readUnsignedInt(); // incorrect
       break;
     default:
       break;
   }
 }
  @Override
  protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg)
      throws Exception {

    ChannelBuffer buf = (ChannelBuffer) msg;

    prefix = buf.toString(buf.readerIndex(), 4, CHARSET);
    buf.skipBytes(prefix.length()); // prefix @NTC by default
    serverId = buf.readUnsignedInt();
    deviceUniqueId = buf.readUnsignedInt();
    int length = buf.readUnsignedShort();
    buf.skipBytes(2); // header and data XOR checksum

    if (length == 0) {
      return null; // keep alive message
    }

    String type = buf.toString(buf.readerIndex(), 3, CHARSET);
    buf.skipBytes(type.length());

    switch (type) {
      case "*>T":
        return processSingle(channel, buf);
      case "*>A":
        return processArray(channel, buf);
      case "*>S":
        return processHandshake(channel, buf);
      default:
        Log.warning(new UnsupportedOperationException(type));
        break;
    }

    return null;
  }
 @Override
 public BlockActionMessage decode(ChannelBuffer buffer) throws IOException {
   int x = buffer.readInt();
   int y = buffer.readUnsignedShort();
   int z = buffer.readInt();
   byte firstByte = buffer.readByte();
   byte secondByte = buffer.readByte();
   short blockId = buffer.readShort();
   return new BlockActionMessage(x, y, z, blockId, firstByte, secondByte);
 }
 @Override
 public PlayerSpawnMessage decode(ChannelBuffer buffer) throws IOException {
   int id = buffer.readInt();
   String name = ChannelBufferUtils.readString(buffer);
   int x = buffer.readInt();
   int y = buffer.readInt();
   int z = buffer.readInt();
   int rotation = buffer.readUnsignedByte();
   int pitch = buffer.readUnsignedByte();
   int item = buffer.readUnsignedShort();
   List<Parameter<?>> parameters = ChannelBufferUtils.readParameters(buffer);
   return new PlayerSpawnMessage(id, name, x, y, z, rotation, pitch, item, parameters);
 }
  private String getUtf(ChannelBuffer buffer) {
    // UTF = short + data;
    int readableBytes = buffer.readableBytes();
    if (readableBytes < 2) {
      throw new IllegalArgumentException("buffer doesn't contains utf data!");
    }

    // 只有长度 没有内容
    if (readableBytes == 2) {
      return "";
    }

    int dataLen = buffer.readUnsignedShort();
    byte[] data = new byte[dataLen];
    buffer.readBytes(data);

    try {
      return new String(data, "UTF-8");
    } catch (UnsupportedEncodingException e) {
      Log.error("解码UTF错误", e);
    }

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

    ChannelBuffer buf = (ChannelBuffer) msg;

    buf.skipBytes(2); // header
    int type = buf.readUnsignedByte();
    buf.readUnsignedShort(); // size

    if (type == MSG_ON_DEMAND
        || type == MSG_POSITION_UPLOAD
        || type == MSG_POSITION_REUPLOAD
        || type == MSG_ALARM
        || type == MSG_REPLY
        || type == MSG_PERIPHERAL) {

      // Create new position
      Position position = new Position();
      position.setProtocol(getProtocolName());

      // Device identification
      if (!identify(readSerialNumber(buf), channel)) {
        return null;
      }
      position.setDeviceId(getDeviceId());

      // Date and time
      Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
      time.clear();
      time.set(Calendar.YEAR, 2000 + ChannelBufferTools.readHexInteger(buf, 2));
      time.set(Calendar.MONTH, ChannelBufferTools.readHexInteger(buf, 2) - 1);
      time.set(Calendar.DAY_OF_MONTH, ChannelBufferTools.readHexInteger(buf, 2));
      time.set(Calendar.HOUR_OF_DAY, ChannelBufferTools.readHexInteger(buf, 2));
      time.set(Calendar.MINUTE, ChannelBufferTools.readHexInteger(buf, 2));
      time.set(Calendar.SECOND, ChannelBufferTools.readHexInteger(buf, 2));
      position.setTime(time.getTime());

      // Location
      position.setLatitude(ChannelBufferTools.readCoordinate(buf));
      position.setLongitude(ChannelBufferTools.readCoordinate(buf));
      position.setSpeed(UnitsConverter.knotsFromKph(ChannelBufferTools.readHexInteger(buf, 4)));
      position.setCourse(ChannelBufferTools.readHexInteger(buf, 4));

      // Flags
      int flags = buf.readUnsignedByte();
      position.setValid((flags & 0x80) != 0);

      if (type == MSG_ALARM) {

        buf.skipBytes(2);

      } else {

        // Odometer
        position.set(Event.KEY_ODOMETER, buf.readUnsignedMedium());

        // Status
        buf.skipBytes(4);

        // Other
        buf.skipBytes(8);
      }

      // TODO: parse extra data
      return position;
    } else if (type == MSG_LOGIN && channel != null) {

      buf.skipBytes(4); // serial number
      buf.readByte(); // reserved

      ChannelBuffer response = ChannelBuffers.dynamicBuffer();
      response.writeByte(0x29);
      response.writeByte(0x29); // header
      response.writeByte(MSG_CONFIRMATION);
      response.writeShort(5); // size
      response.writeByte(buf.readUnsignedByte());
      response.writeByte(type);
      response.writeByte(0); // reserved
      response.writeByte(Crc.xorChecksum(response.toByteBuffer()));
      response.writeByte(0x0D); // ending
      channel.write(response);
    }

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

    ChannelBuffer buf = (ChannelBuffer) msg;

    buf.skipBytes(2); // header
    int type = buf.readUnsignedByte();
    buf.readUnsignedShort(); // length

    String id =
        decodeId(
            buf.readUnsignedByte(), buf.readUnsignedByte(),
            buf.readUnsignedByte(), buf.readUnsignedByte());

    if (type == MSG_HEARTBEAT) {

      if (channel != null) {
        ChannelBuffer response = ChannelBuffers.dynamicBuffer();
        response.writeByte(0x24);
        response.writeByte(0x24); // header
        response.writeByte(MSG_HEARTBEAT); // size
        response.writeShort(5);
        response.writeByte(buf.readUnsignedByte());
        response.writeByte(0); // main order
        response.writeByte(0); // slave order
        response.writeByte(1); // calibration
        response.writeByte(0x0D);
        channel.write(response);
      }

    } else if (type == MSG_POSITION_DATA
        || type == MSG_ROLLCALL_RESPONSE
        || type == MSG_ALARM_DATA
        || type == MSG_BLIND_AREA) {

      Position position = new Position();
      position.setProtocol(getProtocolName());

      if (!identify("1" + id, channel, remoteAddress, false)
          && !identify(id, channel, remoteAddress)) {
        return null;
      }
      position.setDeviceId(getDeviceId());

      DateBuilder dateBuilder =
          new DateBuilder()
              .setYear(BcdUtil.readInteger(buf, 2))
              .setMonth(BcdUtil.readInteger(buf, 2))
              .setDay(BcdUtil.readInteger(buf, 2))
              .setHour(BcdUtil.readInteger(buf, 2))
              .setMinute(BcdUtil.readInteger(buf, 2))
              .setSecond(BcdUtil.readInteger(buf, 2));
      position.setTime(dateBuilder.getDate());

      position.setLatitude(BcdUtil.readCoordinate(buf));
      position.setLongitude(BcdUtil.readCoordinate(buf));
      position.setSpeed(UnitsConverter.knotsFromKph(BcdUtil.readInteger(buf, 4)));
      position.setCourse(BcdUtil.readInteger(buf, 4));

      int flags = buf.readUnsignedByte();
      position.setValid((flags & 0x80) != 0);
      position.set(Position.KEY_SATELLITES, flags & 0x0f);

      position.set(Position.KEY_STATUS, buf.readUnsignedByte());
      position.set("key", buf.readUnsignedByte());
      position.set("oil", buf.readUnsignedShort() / 10.0);
      position.set(Position.KEY_POWER, buf.readUnsignedByte() + buf.readUnsignedByte() / 100.0);
      position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());

      return position;
    }

    return null;
  }
Exemple #11
0
 @Override
 public int readUnsignedShort() {
   return buffer.readUnsignedShort();
 }
Exemple #12
0
 /**
  * Decodes the payload from a Netty buffer in a big switch
  *
  * @param content The content type
  * @param buffer The buffer to read from
  * @param message The message to store the results
  * @throws IndexOutOfBoundsException If a buffer is read beyond its limits
  * @throws NoSuchAlgorithmException
  * @throws SignatureException
  * @throws InvalidKeyException
  * @throws InvalidKeySpecException
  * @throws InvalidKeySpecException
  * @throws IOException
  * @throws DecoderException
  * @throws ASN1Exception
  * @throws UnsupportedEncodingException If UTF-8 is not there
  */
 public static boolean decodePayload(
     final Content content, final ChannelBuffer buffer, final Message message)
     throws InvalidKeyException, SignatureException, NoSuchAlgorithmException,
         InvalidKeySpecException, IOException, DecoderException {
   final int len;
   byte[] me;
   switch (content) {
     case KEY:
       if (buffer.readableBytes() < 20) return false;
       message.setKey0(readID(buffer));
       return true;
     case KEY_KEY:
       if (buffer.readableBytes() < 40) return false;
       message.setKeyKey0(readID(buffer), readID(buffer));
       return true;
     case MAP_KEY_DATA:
       if (buffer.readableBytes() < 4) return false;
       int size = buffer.readInt();
       Map<Number160, Data> result = new HashMap<Number160, Data>(size);
       for (int i = 0; i < size; i++) {
         if (buffer.readableBytes() < 20) return false;
         Number160 key = readID(buffer);
         final Data data = decodeData(new ChannelDecoder(buffer), message.getSender());
         if (data == null) return false;
         if (message.isRequest()) {
           if (data.isProtectedEntry() && message.getPublicKey() == null)
             throw new DecoderException(
                 "You indicated that you want to protect the data, but you did not provide or provided too late a public key.");
           data.setPublicKey(message.getPublicKey());
         }
         result.put(key, data);
       }
       message.setDataMap0(result);
       return true;
     case MAP_KEY_KEY:
       if (buffer.readableBytes() < 4) return false;
       len = buffer.readInt();
       if (buffer.readableBytes() < ((20 + 20) * len)) return false;
       final Map<Number160, Number160> keyMap = new HashMap<Number160, Number160>();
       for (int i = 0; i < len; i++) {
         final Number160 key1 = readID(buffer);
         final Number160 key2 = readID(buffer);
         keyMap.put(key1, key2);
       }
       message.setKeyMap0(keyMap);
       return true;
     case SET_KEYS:
       // can be 31bit long ~ 2GB
       if (buffer.readableBytes() < 4) return false;
       len = buffer.readInt();
       if (buffer.readableBytes() < (20 * len)) return false;
       final Collection<Number160> tmp = new ArrayList<Number160>(len);
       for (int i = 0; i < len; i++) {
         Number160 key = readID(buffer);
         tmp.add(key);
       }
       message.setKeys0(tmp);
       return true;
     case SET_NEIGHBORS:
       if (buffer.readableBytes() < 1) return false;
       len = buffer.readUnsignedByte();
       if (buffer.readableBytes() < (len * PeerAddress.SIZE_IPv4)) return false;
       final Collection<PeerAddress> neighbors = new ArrayList<PeerAddress>(len);
       for (int i = 0; i < len; i++) {
         PeerAddress peerAddress = readPeerAddress(buffer);
         if (peerAddress == null) return false;
         neighbors.add(peerAddress);
       }
       message.setNeighbors0(neighbors);
       return true;
     case SET_TRACKER_DATA:
       if (buffer.readableBytes() < 1) return false;
       len = buffer.readUnsignedByte();
       if (buffer.readableBytes() < (len * (PeerAddress.SIZE_IPv4 + 1))) return false;
       final Collection<TrackerData> trackerDatas = new ArrayList<TrackerData>(len);
       for (int i = 0; i < len; i++) {
         PeerAddress peerAddress = readPeerAddress(buffer);
         if (peerAddress == null) return false;
         byte[] attachment = null;
         int offset = 0;
         int length = 0;
         if (buffer.readableBytes() < 1) return false;
         byte miniHeader = buffer.readByte();
         if (miniHeader != 0) {
           if (buffer.readableBytes() < 4) return false;
           length = buffer.readInt();
           if (buffer.readableBytes() < length) return false;
           attachment = new byte[length];
           buffer.readBytes(attachment);
         }
         trackerDatas.add(
             new TrackerData(peerAddress, message.getSender(), attachment, offset, length));
       }
       message.setTrackerData0(trackerDatas);
       return true;
     case CHANNEL_BUFFER:
       if (buffer.readableBytes() < 4) return false;
       len = buffer.readInt();
       if (buffer.readableBytes() < len) return false;
       // you can only use slice if no execution handler is in place,
       // otherwise, you will overwrite stuff
       final ChannelBuffer tmpBuffer = buffer.slice(buffer.readerIndex(), len);
       buffer.skipBytes(len);
       message.setPayload0(tmpBuffer);
       return true;
     case LONG:
       if (buffer.readableBytes() < 8) return false;
       message.setLong0(buffer.readLong());
       return true;
     case INTEGER:
       if (buffer.readableBytes() < 4) return false;
       message.setInteger0(buffer.readInt());
       return true;
     case PUBLIC_KEY:
     case PUBLIC_KEY_SIGNATURE:
       if (buffer.readableBytes() < 2) return false;
       len = buffer.readUnsignedShort();
       me = new byte[len];
       if (buffer.readableBytes() < len) return false;
       message.setPublicKey0(decodePublicKey(new ChannelDecoder(buffer), me));
       if (content == Content.PUBLIC_KEY_SIGNATURE) {
         message.setHintSign(true);
       }
       return true;
     case EMPTY:
     case RESERVED1:
     case RESERVED2:
     case RESERVED3:
     default:
       return true;
   }
 }
  @Override
  protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg)
      throws Exception {

    ChannelBuffer buf = (ChannelBuffer) msg;

    buf.skipBytes(2); // header
    buf.readUnsignedShort(); // length

    String imei = ChannelBuffers.hexDump(buf.readBytes(7));
    if (!identify(imei, channel, null, false)
        && !identify(imei + Checksum.luhn(Long.parseLong(imei)), channel)) {
      return null;
    }

    int type = buf.readUnsignedShort();

    if (type == MSG_LOCATION_REPORT || type == MSG_LOCATION_REQUEST) {

      String sentence =
          buf.toString(buf.readerIndex(), buf.readableBytes() - 8, Charset.defaultCharset());
      Parser parser = new Parser(PATTERN, sentence);
      if (!parser.matches()) {
        return null;
      }

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

      if (parser.hasNext(15)) {

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

        position.setValid(parser.next().equals("A"));
        position.set(Event.KEY_SATELLITES, parser.next());

        position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG));
        position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG));

        position.setSpeed(parser.nextDouble());
        position.set(Event.KEY_HDOP, parser.nextDouble());
        position.setAltitude(parser.nextDouble());

      } else {

        getLastLocation(position, null);
      }

      position.set(Event.KEY_MCC, parser.nextInt());
      position.set(Event.KEY_MNC, parser.nextInt());
      position.set(Event.KEY_LAC, parser.nextInt());
      position.set(Event.KEY_CELL, parser.nextInt());

      return position;
    }

    return null;
  }
  private Position decodeNormalMessage(
      ChannelBuffer buf, Channel channel, SocketAddress remoteAddress) {

    Position position = new Position();
    position.setProtocol(getProtocolName());

    buf.readByte(); // header

    String id = String.valueOf(Long.parseLong(ChannelBuffers.hexDump(buf.readBytes(5))));
    if (!identify(id, channel, remoteAddress)) {
      return null;
    }
    position.setDeviceId(getDeviceId());

    int version = ChannelBufferTools.readHexInteger(buf, 1);
    buf.readUnsignedByte(); // type
    buf.readBytes(2); // length

    DateBuilder dateBuilder =
        new DateBuilder()
            .setDay(ChannelBufferTools.readHexInteger(buf, 2))
            .setMonth(ChannelBufferTools.readHexInteger(buf, 2))
            .setYear(ChannelBufferTools.readHexInteger(buf, 2))
            .setHour(ChannelBufferTools.readHexInteger(buf, 2))
            .setMinute(ChannelBufferTools.readHexInteger(buf, 2))
            .setSecond(ChannelBufferTools.readHexInteger(buf, 2));
    position.setTime(dateBuilder.getDate());

    double latitude = convertCoordinate(ChannelBufferTools.readHexInteger(buf, 8));
    double longitude = convertCoordinate(ChannelBufferTools.readHexInteger(buf, 9));

    byte flags = buf.readByte();
    position.setValid((flags & 0x1) == 0x1);
    if ((flags & 0x2) == 0) {
      latitude = -latitude;
    }
    position.setLatitude(latitude);
    if ((flags & 0x4) == 0) {
      longitude = -longitude;
    }
    position.setLongitude(longitude);

    position.setSpeed(ChannelBufferTools.readHexInteger(buf, 2));
    position.setCourse(buf.readUnsignedByte() * 2.0);

    if (version == 1) {

      position.set(Event.KEY_SATELLITES, buf.readUnsignedByte());
      position.set(Event.KEY_POWER, buf.readUnsignedByte());

      buf.readByte(); // other flags and sensors

      position.setAltitude(buf.readUnsignedShort());

      int cid = buf.readUnsignedShort();
      int lac = buf.readUnsignedShort();
      if (cid != 0 && lac != 0) {
        position.set(Event.KEY_CID, cid);
        position.set(Event.KEY_LAC, lac);
      }

      position.set(Event.KEY_GSM, buf.readUnsignedByte());

    } else if (version == 2) {

      int fuel = buf.readUnsignedByte() << 8;

      position.set(Event.KEY_STATUS, buf.readUnsignedInt());
      position.set(Event.KEY_ODOMETER, buf.readUnsignedInt());

      fuel += buf.readUnsignedByte();
      position.set(Event.KEY_FUEL, fuel);
    }

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

    ChannelBuffer buf = (ChannelBuffer) msg;
    int type = buf.readUnsignedShort();
    buf.readUnsignedShort(); // length

    if (type == MSG_IDENT || type == MSG_IDENT_FULL) {

      buf.readUnsignedInt(); // id
      int length = buf.readUnsignedShort();
      buf.skipBytes(length);
      length = buf.readUnsignedShort();
      buf.skipBytes(length);
      length = buf.readUnsignedShort();
      String imei = buf.readBytes(length).toString(Charset.defaultCharset());
      identify(imei, channel, remoteAddress);

    } else if (hasDeviceId() && (type == MSG_POINT || type == MSG_ALARM || type == MSG_LOGMSG)) {

      List<Position> positions = new LinkedList<>();

      int recordCount = 1;
      if (type == MSG_LOGMSG) {
        recordCount = buf.readUnsignedShort();
      }

      for (int j = 0; j < recordCount; j++) {
        Position position = new Position();
        position.setProtocol(getProtocolName());
        position.setDeviceId(getDeviceId());

        if (type == MSG_LOGMSG) {
          position.set(Event.KEY_ARCHIVE, true);
          int subtype = buf.readUnsignedShort();
          if (subtype == MSG_ALARM) {
            position.set(Event.KEY_ALARM, true);
          }
          if (buf.readUnsignedShort() > buf.readableBytes()) {
            lastIndex += 1;
            break; // workaround for device bug
          }
          lastIndex = buf.readUnsignedInt();
          position.set(Event.KEY_INDEX, lastIndex);
        } else {
          newIndex = buf.readUnsignedInt();
        }

        position.setTime(new Date(buf.readUnsignedInt() * 1000));
        position.setLatitude(buf.readInt() * 180.0 / 0x7FFFFFFF);
        position.setLongitude(buf.readInt() * 180.0 / 0x7FFFFFFF);
        position.setSpeed(buf.readUnsignedInt() * 0.01);
        position.setCourse(buf.readUnsignedShort() * 0.01);
        position.setAltitude(buf.readUnsignedShort() * 0.01);

        int satellites = buf.readUnsignedByte();
        position.setValid(satellites >= 3);
        position.set(Event.KEY_SATELLITES, satellites);

        position.set(Event.KEY_GSM, buf.readUnsignedByte());
        position.set(Event.KEY_ODOMETER, buf.readUnsignedInt());

        long extraFlags = buf.readLong();

        if (BitUtil.check(extraFlags, 0)) {
          int count = buf.readUnsignedShort();
          for (int i = 1; i <= count; i++) {
            position.set(Event.PREFIX_ADC + i, buf.readUnsignedShort());
          }
        }

        if (BitUtil.check(extraFlags, 1)) {
          int size = buf.readUnsignedShort();
          position.set("can", buf.toString(buf.readerIndex(), size, Charset.defaultCharset()));
          buf.skipBytes(size);
        }

        if (BitUtil.check(extraFlags, 2)) {
          position.set("passenger", ChannelBuffers.hexDump(buf.readBytes(buf.readUnsignedShort())));
        }

        if (type == MSG_ALARM) {
          position.set(Event.KEY_ALARM, true);
          byte[] response = {(byte) 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
          channel.write(ChannelBuffers.wrappedBuffer(response));
        }

        buf.readUnsignedInt(); // crc

        positions.add(position);
      }

      requestArchive(channel);

      return positions;
    }

    return null;
  }
  private ParseResult parsePosition(ChannelBuffer buf) {
    Position position = new Position();
    position.setProtocol(getProtocolName());

    position.setDeviceId(getDeviceId());

    int format;
    if (buf.getUnsignedByte(buf.readerIndex()) == 0) {
      format = buf.readUnsignedShort();
    } else {
      format = buf.readUnsignedByte();
    }
    position.set("format", format);

    long index = buf.readUnsignedInt();
    position.set(Event.KEY_INDEX, index);

    position.set(Event.KEY_EVENT, buf.readUnsignedShort());

    buf.skipBytes(6); // event time

    position.set(Event.KEY_ALARM, buf.readUnsignedByte());
    position.set(Event.KEY_STATUS, buf.readUnsignedByte());
    position.set(Event.KEY_GSM, buf.readUnsignedByte());

    if (isFormat(format, F10, F20, F30)) {
      position.set(Event.KEY_OUTPUT, buf.readUnsignedShort());
    } else if (isFormat(format, F40, F50, F51, F52)) {
      position.set(Event.KEY_OUTPUT, buf.readUnsignedByte());
    }

    if (isFormat(format, F10, F20, F30, F40)) {
      position.set(Event.KEY_INPUT, buf.readUnsignedShort());
    } else if (isFormat(format, F50, F51, F52)) {
      position.set(Event.KEY_INPUT, buf.readUnsignedByte());
    }

    position.set(Event.KEY_POWER, buf.readUnsignedShort() * 0.001);
    position.set(Event.KEY_BATTERY, buf.readUnsignedShort());

    if (isFormat(format, F10, F20, F30)) {
      position.set(Event.PREFIX_TEMP + 1, buf.readShort());
    }

    if (isFormat(format, F10, F20, F50, F52)) {
      position.set(Event.PREFIX_ADC + 1, buf.readUnsignedShort());
      position.set(Event.PREFIX_ADC + 2, buf.readUnsignedShort());
    }

    // Impulse counters
    if (isFormat(format, F20, F50, F51, F52)) {
      buf.readUnsignedInt();
      buf.readUnsignedInt();
    }

    if (isFormat(format, F20, F50, F51, F52)) {
      int locationStatus = buf.readUnsignedByte();
      position.setValid(BitUtil.check(locationStatus, 1));

      DateBuilder dateBuilder =
          new DateBuilder()
              .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
              .setDateReverse(
                  buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
      position.setTime(dateBuilder.getDate());

      position.setLatitude(buf.readFloat() / Math.PI * 180);
      position.setLongitude(buf.readFloat() / Math.PI * 180);
      position.setSpeed(buf.readFloat());
      position.setCourse(buf.readUnsignedShort());

      position.set(Event.KEY_ODOMETER, buf.readFloat());

      position.set("segment", buf.readFloat()); // last segment

      // Segment times
      buf.readUnsignedShort();
      buf.readUnsignedShort();
    }

    // Other
    if (isFormat(format, F51, F52)) {
      buf.readUnsignedShort();
      buf.readByte();
      buf.readUnsignedShort();
      buf.readUnsignedShort();
      buf.readByte();
      buf.readUnsignedShort();
      buf.readUnsignedShort();
      buf.readByte();
      buf.readUnsignedShort();
    }

    // Four temperature sensors
    if (isFormat(format, F40, F52)) {
      buf.readByte();
      buf.readByte();
      buf.readByte();
      buf.readByte();
    }

    return new ParseResult(index, position);
  }
  @Override
  protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg)
      throws Exception {

    ChannelBuffer buf = (ChannelBuffer) msg;

    if (buf.getUnsignedShort(buf.readerIndex()) == 0xfe02) {
      if (channel != null) {
        channel.write(buf, remoteAddress); // keep-alive message
      }
      return null;
    }

    buf.skipBytes(2); // prefix
    buf.readUnsignedShort(); // checksum
    buf.readUnsignedShort(); // length
    int index = buf.readUnsignedShort();

    long id = buf.readLong();
    if (!identify(String.valueOf(id), channel, remoteAddress)) {
      return null;
    }

    sendResponse(channel, remoteAddress, id, index);

    List<Position> positions = new LinkedList<>();

    while (buf.readableBytes() >= MIN_DATA_LENGTH) {

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

      if (longDate) {

        DateBuilder dateBuilder =
            new DateBuilder()
                .setDate(buf.readUnsignedShort(), buf.readUnsignedByte(), buf.readUnsignedByte())
                .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
        position.setTime(dateBuilder.getDate());

        buf.skipBytes(7 + 7);

      } else {

        position.setFixTime(new Date(buf.readUnsignedInt() * 1000));
        position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000));
        buf.readUnsignedInt(); // send time
      }

      position.setValid(true);
      position.setLongitude(buf.readInt() * 0.000001);
      position.setLatitude(buf.readInt() * 0.000001);
      position.setCourse(buf.readUnsignedShort());

      position.set(Position.KEY_TYPE, buf.readUnsignedByte());
      position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 0.1);
      position.set(Position.KEY_HDOP, buf.readUnsignedShort() * 0.1);
      position.set(Position.KEY_INPUT, buf.readUnsignedByte());

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

      position.set(Position.KEY_OUTPUT, buf.readUnsignedByte());
      position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort() * 0.001);

      position.set("driver", readString(buf));

      position.set(Position.PREFIX_TEMP + 1, buf.readShort() * 0.1);
      position.set(Position.PREFIX_TEMP + 2, buf.readShort() * 0.1);

      position.set("message", readString(buf));

      if (custom) {
        String form = this.form;
        if (form == null) {
          form = readString(buf).substring("%CI".length());
        }
        readCustomData(position, buf, form);
      }

      positions.add(position);
    }

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

    ChannelBuffer buf = (ChannelBuffer) msg;

    buf.readUnsignedByte(); // marker
    int version = buf.readUnsignedByte();

    String imei;
    if ((version & 0x80) != 0) {
      imei = String.valueOf((buf.readUnsignedInt() << (3 * 8)) | buf.readUnsignedMedium());
    } else {
      imei = String.valueOf(imeiFromUnitId(buf.readUnsignedMedium()));
    }

    buf.readUnsignedShort(); // length

    int selector = DEFAULT_SELECTOR;
    if ((version & 0x40) != 0) {
      selector = buf.readUnsignedMedium();
    }

    Position position = new Position();
    position.setProtocol(getProtocolName());
    if (!identify(imei, channel, remoteAddress)) {
      return null;
    }

    position.setDeviceId(getDeviceId());

    int event = buf.readUnsignedByte();
    position.set(Event.KEY_EVENT, event);
    position.set("event-info", buf.readUnsignedByte());

    if ((selector & 0x0008) != 0) {
      position.setValid((buf.readUnsignedByte() & 0x40) != 0);
    } else {
      return null; // no location data
    }

    if ((selector & 0x0004) != 0) {
      buf.skipBytes(4); // snapshot time
    }

    if ((selector & 0x0008) != 0) {
      position.setTime(new Date(buf.readUnsignedInt() * 1000));
      position.setLatitude(buf.readInt() / 1000000.0);
      position.setLongitude(buf.readInt() / 1000000.0);
      position.set(Event.KEY_SATELLITES, buf.readUnsignedByte());
    }

    if ((selector & 0x0010) != 0) {
      position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
      buf.readUnsignedByte(); // maximum speed
      position.setCourse(buf.readUnsignedByte() * 2.0);
    }

    if ((selector & 0x0040) != 0) {
      position.set(Event.KEY_INPUT, buf.readUnsignedByte());
    }

    if ((selector & 0x0020) != 0) {
      position.set(Event.PREFIX_ADC + 1, buf.readUnsignedShort());
      position.set(Event.PREFIX_ADC + 2, buf.readUnsignedShort());
      position.set(Event.PREFIX_ADC + 3, buf.readUnsignedShort());
      position.set(Event.PREFIX_ADC + 4, buf.readUnsignedShort());
    }

    if ((selector & 0x8000) != 0) {
      position.set(Event.KEY_POWER, buf.readUnsignedShort() / 1000.0);
      position.set(Event.KEY_BATTERY, buf.readUnsignedShort());
    }

    // Pulse rate 1
    if ((selector & 0x10000) != 0) {
      buf.readUnsignedShort();
      buf.readUnsignedInt();
    }

    // Pulse rate 2
    if ((selector & 0x20000) != 0) {
      buf.readUnsignedShort();
      buf.readUnsignedInt();
    }

    if ((selector & 0x0080) != 0) {
      position.set("trip1", buf.readUnsignedInt());
    }

    if ((selector & 0x0100) != 0) {
      position.set("trip2", buf.readUnsignedInt());
    }

    if ((selector & 0x0040) != 0) {
      position.set(Event.KEY_OUTPUT, buf.readUnsignedByte());
    }

    if ((selector & 0x0200) != 0) {
      position.set(
          Event.KEY_RFID, (((long) buf.readUnsignedShort()) << 32) + buf.readUnsignedInt());
    }

    if ((selector & 0x0400) != 0) {
      buf.readUnsignedByte(); // Keypad
    }

    if ((selector & 0x0800) != 0) {
      position.setAltitude(buf.readShort());
    }

    if ((selector & 0x2000) != 0) {
      buf.readUnsignedShort(); // snapshot counter
    }

    if ((selector & 0x4000) != 0) {
      buf.skipBytes(8); // state flags
    }

    if ((selector & 0x80000) != 0) {
      buf.skipBytes(11); // cell info
    }

    if ((selector & 0x1000) != 0) {
      decodeEventData(event, buf);
    }

    if (Context.getConfig().getBoolean(getProtocolName() + ".can")
        && buf.readable()
        && (selector & 0x1000) != 0
        && event == EVENT_DATA) {

      decodeCanData(buf, position);
    }

    return position;
  }
  private void decodeCanData(ChannelBuffer buf, Position position) {

    buf.readUnsignedMedium(); // packet identifier
    buf.readUnsignedByte(); // version
    int count = buf.readUnsignedByte();
    buf.readUnsignedByte(); // batch count
    buf.readUnsignedShort(); // selector bit
    buf.readUnsignedInt(); // timestamp

    buf.skipBytes(8);

    ArrayList<ChannelBuffer> values = new ArrayList<>(count);

    for (int i = 0; i < count; i++) {
      values.add(buf.readBytes(8));
    }

    for (int i = 0; i < count; i++) {
      ChannelBuffer value = values.get(i);
      switch (buf.readInt()) {
        case 0x20D:
          position.set(Event.KEY_RPM, ChannelBuffers.swapShort(value.readShort()));
          position.set("diesel-temperature", ChannelBuffers.swapShort(value.readShort()) * 0.1);
          position.set("battery-voltage", ChannelBuffers.swapShort(value.readShort()) * 0.01);
          position.set("supply-air-temp-dep1", ChannelBuffers.swapShort(value.readShort()) * 0.1);
          break;
        case 0x30D:
          position.set("active-alarm", ChannelBuffers.hexDump(value));
          break;
        case 0x40C:
          position.set("air-temp-dep1", ChannelBuffers.swapShort(value.readShort()) * 0.1);
          position.set("air-temp-dep2", ChannelBuffers.swapShort(value.readShort()) * 0.1);
          break;
        case 0x40D:
          position.set("cold-unit-state", ChannelBuffers.hexDump(value));
          break;
        case 0x50C:
          position.set("defrost-temp-dep1", ChannelBuffers.swapShort(value.readShort()) * 0.1);
          position.set("defrost-temp-dep2", ChannelBuffers.swapShort(value.readShort()) * 0.1);
          break;
        case 0x50D:
          position.set("condenser-pressure", ChannelBuffers.swapShort(value.readShort()) * 0.1);
          position.set("suction-pressure", ChannelBuffers.swapShort(value.readShort()) * 0.1);
          break;
        case 0x58C:
          value.readByte();
          value.readShort(); // index
          switch (value.readByte()) {
            case 0x01:
              position.set("setpoint-zone1", ChannelBuffers.swapInt(value.readInt()) * 0.1);
              break;
            case 0x02:
              position.set("setpoint-zone2", ChannelBuffers.swapInt(value.readInt()) * 0.1);
              break;
            case 0x05:
              position.set("unit-type", ChannelBuffers.swapInt(value.readInt()));
              break;
            case 0x13:
              position.set("diesel-hours", ChannelBuffers.swapInt(value.readInt()) / 60 / 60);
              break;
            case 0x14:
              position.set("electric-hours", ChannelBuffers.swapInt(value.readInt()) / 60 / 60);
              break;
            case 0x17:
              position.set("service-indicator", ChannelBuffers.swapInt(value.readInt()));
              break;
            case 0x18:
              position.set("software-version", ChannelBuffers.swapInt(value.readInt()) * 0.01);
              break;
            default:
              break;
          }
          break;
        default:
          Log.warning(new UnsupportedOperationException());
          break;
      }
    }
  }
Exemple #20
0
 public static MacAddress read6Bytes(ChannelBuffer c) throws OFParseError {
   long raw = c.readUnsignedInt() << 16 | c.readUnsignedShort();
   return MacAddress.of(raw);
 }
 private void readCustomData(Position position, ChannelBuffer buf, String form) {
   String[] keys = form.substring(1).split("%");
   for (String key : keys) {
     switch (key) {
       case "SA":
         position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
         break;
       case "MV":
         position.set(Position.KEY_POWER, buf.readUnsignedShort());
         break;
       case "BV":
         position.set(Position.KEY_BATTERY, buf.readUnsignedShort());
         break;
       case "GQ":
         position.set(Position.KEY_GSM, buf.readUnsignedByte());
         break;
       case "CE":
         position.set(Position.KEY_CID, buf.readUnsignedInt());
         break;
       case "LC":
         position.set(Position.KEY_LAC, buf.readUnsignedShort());
         break;
       case "CN":
         buf.readUnsignedInt(); // mcc + mnc
         break;
       case "RL":
         buf.readUnsignedByte(); // rxlev
         break;
       case "PC":
         buf.readUnsignedInt(); // pulse count
         break;
       case "AT":
         position.setAltitude(buf.readUnsignedInt());
         break;
       case "RP":
         position.set(Position.KEY_RPM, buf.readUnsignedShort());
         break;
       case "GS":
         buf.readUnsignedByte(); // gsm status
         break;
       case "DT":
         position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() == 1);
         break;
       case "VN":
         position.set(Position.KEY_VIN, readString(buf));
         break;
       case "MF":
         buf.readUnsignedShort(); // mass air flow rate
         break;
       case "EL":
         buf.readUnsignedByte(); // engine load
         break;
       case "TR":
         position.set(Position.KEY_THROTTLE, buf.readUnsignedByte());
         break;
       case "ET":
         buf.readUnsignedShort(); // engine coolant temp
         break;
       case "FL":
         position.set(Position.KEY_FUEL, buf.readUnsignedByte());
         break;
       case "ML":
         buf.readUnsignedByte(); // mil status
         break;
       case "FC":
         buf.readUnsignedInt(); // fuel used
         break;
       case "CI":
         readString(buf); // format string
         break;
       case "AV1":
         position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort());
         break;
       case "NC":
         readString(buf); // gsm neighbor cell info
         break;
       case "SM":
         buf.readUnsignedShort(); // max speed between reports
         break;
       case "GL":
         readString(buf); // google link
         break;
       case "MA":
         readString(buf); // mac address
         break;
       default:
         break;
     }
   }
 }
  @Override
  protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg)
      throws Exception {

    ChannelBuffer buf = (ChannelBuffer) msg;

    buf.readUnsignedShort(); // device id
    buf.readUnsignedByte(); // length

    int type = buf.readUnsignedByte();

    DeviceSession deviceSession;
    if (type == MSG_IMEI) {
      deviceSession =
          getDeviceSession(
              channel, remoteAddress, buf.readBytes(15).toString(StandardCharsets.US_ASCII));
    } else {
      deviceSession = getDeviceSession(channel, remoteAddress);
    }

    if (deviceSession == null) {
      return null;
    }

    if (BitUtil.to(type, 2) == 0) {

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

      buf.readUnsignedByte(); // firmware version
      buf.readUnsignedShort(); // index

      position.set(Position.KEY_STATUS, buf.readUnsignedShort());

      position.setValid(true);
      position.setLatitude(buf.readFloat());
      position.setLongitude(buf.readFloat());
      position.setCourse(buf.readUnsignedShort() * 0.1);
      position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort() * 0.1));

      buf.readUnsignedByte(); // acceleration

      position.setAltitude(buf.readUnsignedShort());

      position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1);
      position.set(Position.KEY_SATELLITES, buf.readUnsignedByte() & 0x0f);

      position.setTime(new Date(buf.readUnsignedInt() * 1000));

      position.set(Position.KEY_POWER, buf.readUnsignedShort());
      position.set(Position.KEY_BATTERY, buf.readUnsignedShort());

      if (BitUtil.check(type, 2)) {
        buf.skipBytes(4);
      }

      if (BitUtil.check(type, 3)) {
        buf.skipBytes(12);
      }

      if (BitUtil.check(type, 4)) {
        buf.skipBytes(8);
      }

      if (BitUtil.check(type, 5)) {
        buf.skipBytes(9);
      }

      if (BitUtil.check(type, 6)) {
        buf.skipBytes(buf.getUnsignedByte(buf.readerIndex()));
      }

      if (BitUtil.check(type, 7)) {
        position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
      }

      return position;
    }

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

    ChannelBuffer buf = (ChannelBuffer) msg;

    buf.readUnsignedByte(); // header
    int length = (buf.readUnsignedShort() & 0x7fff) + 3;

    List<Position> positions = new LinkedList<>();
    Set<Integer> tags = new HashSet<>();
    boolean hasLocation = false;
    Position position = new Position();
    position.setProtocol(getProtocolName());

    while (buf.readerIndex() < length) {

      // Check if new message started
      int tag = buf.readUnsignedByte();
      if (tags.contains(tag)) {
        if (hasLocation && position.getFixTime() != null) {
          positions.add(position);
        }
        tags.clear();
        hasLocation = false;
        position = new Position();
      }
      tags.add(tag);

      switch (tag) {
        case TAG_IMEI:
          getDeviceSession(
              channel, remoteAddress, buf.readBytes(15).toString(StandardCharsets.US_ASCII));
          break;

        case TAG_DATE:
          position.setTime(new Date(buf.readUnsignedInt() * 1000));
          break;

        case TAG_COORDINATES:
          hasLocation = true;
          position.setValid((buf.readUnsignedByte() & 0xf0) == 0x00);
          position.setLatitude(buf.readInt() / 1000000.0);
          position.setLongitude(buf.readInt() / 1000000.0);
          break;

        case TAG_SPEED_COURSE:
          position.setSpeed(buf.readUnsignedShort() * 0.0539957);
          position.setCourse(buf.readUnsignedShort() * 0.1);
          break;

        case TAG_ALTITUDE:
          position.setAltitude(buf.readShort());
          break;

        case TAG_STATUS:
          int status = buf.readUnsignedShort();
          position.set(Position.KEY_IGNITION, BitUtil.check(status, 9));
          position.set(Position.KEY_ALARM, BitUtil.check(status, 15));
          position.set(Position.KEY_POWER, BitUtil.check(status, 2));
          break;

        case TAG_DIGITAL_INPUTS:
          int input = buf.readUnsignedShort();
          for (int i = 0; i < 16; i++) {
            position.set(Position.PREFIX_IO + (i + 1), BitUtil.check(input, i));
          }
          break;

        case TAG_DIGITAL_OUTPUTS:
          int output = buf.readUnsignedShort();
          for (int i = 0; i < 16; i++) {
            position.set(Position.PREFIX_IO + (i + 17), BitUtil.check(output, i));
          }
          break;

        case TAG_INPUT_VOLTAGE1:
          position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort() / 1000.0);
          break;

        case TAG_INPUT_VOLTAGE2:
          position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort() / 1000.0);
          break;

        case TAG_INPUT_VOLTAGE3:
          position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort() / 1000.0);
          break;

        case TAG_INPUT_VOLTAGE4:
          position.set(Position.PREFIX_ADC + 4, buf.readUnsignedShort() / 1000.0);
          break;

        case TAG_XT1:
        case TAG_XT2:
        case TAG_XT3:
          buf.skipBytes(16);
          break;

        default:
          break;
      }
    }

    if (hasLocation && position.getFixTime() != null) {
      positions.add(position);
    }

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

    sendReply(channel, buf.readUnsignedShort());

    for (Position p : positions) {
      p.setDeviceId(deviceSession.getDeviceId());
    }

    if (positions.isEmpty()) {
      return null;
    }

    return positions;
  }
  private List<Position> decodeBinaryMessage(Channel channel, ChannelBuffer buf) {
    List<Position> positions = new LinkedList<>();

    String flag = buf.toString(2, 1, Charset.defaultCharset());
    int index = ChannelBufferTools.find(buf, 0, buf.readableBytes(), ",");

    // Identification
    String imei = buf.toString(index + 1, 15, Charset.defaultCharset());
    if (!identify(imei, channel)) {
      return null;
    }

    buf.skipBytes(index + 1 + 15 + 1 + 3 + 1 + 2 + 2 + 4);

    while (buf.readableBytes() >= 0x34) {

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

      // Event
      position.set(Event.KEY_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
      position.set(Event.KEY_SATELLITES, buf.readUnsignedByte());

      // GSM Signal
      position.set(Event.KEY_GSM, buf.readUnsignedByte());

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

      // Course
      position.setCourse(buf.readUnsignedShort());

      // HDOP
      position.set(Event.KEY_HDOP, buf.readUnsignedShort() * 0.1);

      // Altitude
      position.setAltitude(buf.readUnsignedShort());

      // Other
      position.set(Event.KEY_ODOMETER, buf.readUnsignedInt());
      position.set("runtime", buf.readUnsignedInt());
      position.set(
          Event.KEY_CELL,
          buf.readUnsignedShort()
              + "|"
              + buf.readUnsignedShort()
              + "|"
              + buf.readUnsignedShort()
              + "|"
              + buf.readUnsignedShort());
      position.set(Event.KEY_STATUS, buf.readUnsignedShort());

      // ADC
      position.set(Event.PREFIX_ADC + 1, buf.readUnsignedShort());
      position.set(Event.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
      position.set(Event.KEY_POWER, buf.readUnsignedShort());

      buf.readUnsignedInt(); // geo-fence
      positions.add(position);
    }

    // Delete recorded data
    if (channel != null) {
      StringBuilder command = new StringBuilder("@@");
      command.append(flag).append(27 + positions.size() / 10).append(",");
      command.append(imei).append(",CCC,").append(positions.size()).append("*");
      int checksum = 0;
      for (int i = 0; i < command.length(); i += 1) checksum += command.charAt(i);
      command.append(String.format("%02x", checksum & 0xff).toUpperCase());
      command.append("\r\n");
      channel.write(command.toString());
    }

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

    ChannelBuffer buf = (ChannelBuffer) msg;

    buf.skipBytes(2); // header
    ChannelBuffer id = buf.readBytes(12);
    buf.readUnsignedByte(); // separator
    int type = buf.readUnsignedByte();
    buf.readUnsignedShort(); // length

    if (type == MSG_LOGIN) {

      int command = buf.readUnsignedByte(); // 0x00 - heartbeat

      if (command == 0x01) {
        String imei = buf.toString(buf.readerIndex(), 15, StandardCharsets.US_ASCII);
        DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
        if (deviceSession != null && channel != null) {
          ChannelBuffer response = ChannelBuffers.dynamicBuffer();
          response.writeByte(0x48);
          response.writeByte(0x52); // header
          response.writeBytes(id);
          response.writeByte(0x2c); // separator
          response.writeByte(type);
          response.writeShort(0x0002); // length
          response.writeShort(0x8000);
          response.writeShort(0x0000); // checksum
          channel.write(response);
        }
      }

    } else if (type == MSG_GPS) {

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

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

      position.setTime(new Date(buf.readUnsignedInt() * 1000));

      int flags = buf.readUnsignedByte();

      position.setValid(true);
      position.setLatitude(convertCoordinate(buf.readUnsignedInt(), !BitUtil.check(flags, 0)));
      position.setLongitude(convertCoordinate(buf.readUnsignedInt(), !BitUtil.check(flags, 1)));

      position.setSpeed(buf.readUnsignedByte());
      position.setCourse(buf.readUnsignedByte());

      position.set(Position.KEY_LAC, buf.readUnsignedShort());
      position.set(Position.KEY_CID, buf.readUnsignedShort());

      return position;
    }

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

    ChannelBuffer buf = (ChannelBuffer) msg;

    buf.skipBytes(4); // system code
    int type = buf.readUnsignedByte();
    long deviceUniqueId = buf.readUnsignedInt();

    if (type != MSG_CLIENT_SERIAL) {
      buf.readUnsignedShort(); // communication control
    }
    byte packetNumber = buf.readByte();

    // Send reply
    sendReply(channel, deviceUniqueId, packetNumber);

    // Parse location
    if (type == MSG_CLIENT_STATUS) {
      Position position = new Position();
      position.setProtocol(getProtocolName());

      // Device identifier
      if (!identify(String.valueOf(deviceUniqueId), channel)) {
        return null;
      }
      position.setDeviceId(getDeviceId());

      buf.readUnsignedByte(); // hardware version
      buf.readUnsignedByte(); // software version
      buf.readUnsignedByte(); // protocol version

      // Status
      position.set(Event.KEY_STATUS, buf.getUnsignedByte(buf.readerIndex()) & 0x0f);

      int operator = (buf.readUnsignedByte() & 0xf0) << 4;
      operator += buf.readUnsignedByte();

      buf.readUnsignedByte(); // reason data
      buf.readUnsignedByte(); // reason
      buf.readUnsignedByte(); // mode
      buf.readUnsignedInt(); // IO

      operator <<= 8;
      operator += buf.readUnsignedByte();
      position.set("operator", operator);

      buf.readUnsignedInt(); // ADC
      buf.readUnsignedMedium(); // Odometer
      buf.skipBytes(6); // multi-purpose data

      buf.readUnsignedShort(); // gps fix
      buf.readUnsignedByte(); // location status
      buf.readUnsignedByte(); // mode 1
      buf.readUnsignedByte(); // mode 2

      position.setValid(buf.readUnsignedByte() >= 3); // satellites

      // Location data
      position.setLongitude(buf.readInt() / Math.PI * 180 / 100000000);
      position.setLatitude(buf.readInt() / Math.PI * 180 / 100000000.0);
      position.setAltitude(buf.readInt() * 0.01);
      position.setSpeed(UnitsConverter.knotsFromMps(buf.readInt() * 0.01));
      position.setCourse(buf.readUnsignedShort() / Math.PI * 180.0 / 1000.0);

      // Time
      Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
      time.clear();
      time.set(Calendar.SECOND, buf.readUnsignedByte());
      time.set(Calendar.MINUTE, buf.readUnsignedByte());
      time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte());
      time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte());
      time.set(Calendar.MONTH, buf.readUnsignedByte() - 1);
      time.set(Calendar.YEAR, buf.readUnsignedShort());
      position.setTime(time.getTime());
      return position;
    }

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

    ChannelBuffer buf = (ChannelBuffer) msg;

    buf.readUnsignedByte(); // protocol
    buf.readUnsignedShort(); // length
    int index = buf.readUnsignedByte() >> 3;

    if (channel != null) {
      ChannelBuffer response = ChannelBuffers.copiedBuffer("^" + index, Charset.defaultCharset());
      channel.write(response, remoteAddress);
    }

    String id = String.valueOf(buf.readUnsignedInt());
    if (!identify(id, channel, remoteAddress)) {
      return null;
    }

    List<Position> positions = new LinkedList<>();

    while (buf.readableBytes() > 2) {

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

      int end = buf.readerIndex() + buf.readUnsignedByte();

      position.setTime(new Date(buf.readUnsignedInt() * 1000));

      int flags = buf.readUnsignedByte();
      position.set(Event.KEY_SATELLITES, BitUtil.range(flags, 2));
      position.setValid(BitUtil.range(flags, 0, 2) > 0);

      // Latitude
      double lat = buf.readUnsignedMedium();
      lat = lat * -180 / 16777216 + 90;
      position.setLatitude(lat);

      // Longitude
      double lon = buf.readUnsignedMedium();
      lon = lon * 360 / 16777216 - 180;
      position.setLongitude(lon);

      // Status
      flags = buf.readUnsignedByte();
      position.set(Event.KEY_IGNITION, BitUtil.check(flags, 0));
      position.set(Event.KEY_GSM, BitUtil.range(flags, 2, 3));
      position.setCourse((BitUtil.range(flags, 5) * 45 + 180) % 360);

      // Speed
      int speed = buf.readUnsignedByte();
      if (speed < 250) {
        position.setSpeed(UnitsConverter.knotsFromKph(speed));
      }

      while (buf.readerIndex() < end) {

        int type = buf.readUnsignedByte();
        int length = buf.readUnsignedByte();
        if (length == 255) {
          length += buf.readUnsignedByte();
        }

        switch (type) {
          case 2:
            position.set(Event.KEY_ODOMETER, buf.readUnsignedMedium());
            break;
          case 5:
            position.set(Event.KEY_INPUT, buf.readUnsignedByte());
            break;
          case 6:
            {
              int n = buf.readUnsignedByte() >> 4;
              if (n < 2) {
                position.set(Event.PREFIX_ADC + n, readSwappedFloat(buf));
              } else {
                position.set("di" + (n - 2), readSwappedFloat(buf));
              }
            }
            break;
          case 7:
            {
              int alarm = buf.readUnsignedByte();
              buf.readUnsignedByte();
              if (BitUtil.check(alarm, 5)) {
                position.set(Event.KEY_ALARM, BitUtil.range(alarm, 0, 4));
              }
            }
            break;
          case 8:
            position.set("antihijack", buf.readUnsignedByte());
            break;
          case 9:
            position.set("authorized", ChannelBufferTools.readHexString(buf, 16));
            break;
          case 10:
            position.set("unauthorized", ChannelBufferTools.readHexString(buf, 16));
            break;
          case 24:
            {
              Set<Integer> temps = new LinkedHashSet<>();
              int temp = buf.readUnsignedByte();
              for (int i = 3; i >= 0; i--) {
                int n = (temp >> (2 * i)) & 0x03;
                if (!temps.contains(n)) {
                  temps.add(n);
                }
              }
              for (int n : temps) {
                position.set(Event.PREFIX_TEMP + n, buf.readUnsignedByte());
              }
            }
            break;
          case 28:
            position.set("weight", buf.readUnsignedShort());
            buf.readUnsignedByte();
            break;
          case 90:
            position.set(Event.KEY_POWER, readSwappedFloat(buf));
            break;
          case 101:
            position.set(Event.KEY_OBD_SPEED, buf.readUnsignedByte());
            break;
          case 102:
            position.set(Event.KEY_RPM, buf.readUnsignedByte() * 50);
            break;
          case 107:
            {
              int fuel = buf.readUnsignedShort();
              switch (fuel >> 14) {
                case 1:
                  position.set(Event.KEY_FUEL, (fuel & 0x3fff) * 0.4 + "%");
                  break;
                case 2:
                  position.set(Event.KEY_FUEL, (fuel & 0x3fff) * 0.5 + " l");
                  break;
                case 3:
                  position.set(Event.KEY_FUEL, (fuel & 0x3fff) * -0.5 + " l");
                  break;
              }
            }
            break;
          case 108:
            position.set(Event.KEY_OBD_ODOMETER, buf.readUnsignedInt() * 5);
            break;
          case 150:
            position.set("door", buf.readUnsignedByte());
            break;
          default:
            buf.skipBytes(length);
            break;
        }
      }

      positions.add(position);
    }

    return positions;
  }