private static String formatSentence(Position position) {

    StringBuilder s = new StringBuilder("$GPRMC,");

    try (Formatter f = new Formatter(s, Locale.ENGLISH)) {

      Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.ENGLISH);
      calendar.setTimeInMillis(position.getFixTime().getTime());

      f.format("%1$tH%1$tM%1$tS.%1$tL,A,", calendar);

      double lat = position.getLatitude();
      double lon = position.getLongitude();
      f.format("%02d%07.4f,%c,", (int) Math.abs(lat), Math.abs(lat) % 1 * 60, lat < 0 ? 'S' : 'N');
      f.format("%03d%07.4f,%c,", (int) Math.abs(lon), Math.abs(lon) % 1 * 60, lon < 0 ? 'W' : 'E');

      f.format("%.2f,%.2f,", position.getSpeed(), position.getCourse());
      f.format("%1$td%1$tm%1$ty,,", calendar);
    }

    s.append(Checksum.nmea(s.toString()));

    return s.toString();
  }
  @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 static boolean validateImei(long imei) {
   return Checksum.luhn(imei / 10) == imei % 10;
 }