001package jmri.jmrix.ipocs.protocol.packets;
002
003import java.nio.ByteBuffer;
004import java.util.ServiceLoader;
005
006import org.slf4j.Logger;
007import org.slf4j.LoggerFactory;
008
009/**
010 * Base packet functionality
011 *
012 * @author Fredrik Elestedt Copyright (C) 2020
013 * @since 4.21.2
014 */
015public abstract class Packet {
016  private final static Logger log = LoggerFactory.getLogger(Packet.class);
017  private byte length;
018  private byte ack;
019
020  public abstract byte getId();
021
022  public byte getAck() {
023    return ack;
024  }
025
026  public void setAck(byte ack) {
027    this.ack = ack;
028  }
029
030  public byte getLength() {
031      return length;
032  }
033
034  public void setLength(byte length) {
035      this.length = length;
036  }
037
038  public static Packet parse(ByteBuffer buffer)  {
039    Packet pkt = null;
040    {
041      byte id = buffer.get();
042      // Get length
043      byte length = buffer.get();
044      // get if ack is requested
045      byte ack = buffer.get();
046      // Find packet type
047      ServiceLoader<Packet> loader = ServiceLoader.load(Packet.class);
048      for (Packet implClass : loader) {
049        if (implClass.getId() == id) {
050          pkt = implClass;
051          pkt.ack = ack;
052          pkt.length = length;
053          break;
054        }
055      }
056      if (pkt == null) {
057        log.error("No packet found for identifier {}", id);
058        buffer.position(buffer.position() + length - 3);
059        return null;
060      }
061      log.debug("Found packet type {}", pkt.getClass().getSimpleName());
062    }
063    // parse the rest of the packet
064    pkt.parseSpecific(buffer);
065    return pkt;
066  }
067
068  public ByteBuffer serialize() {
069    byte[] specific = serializeSpecific();
070    length = (byte)(specific.length + 3);
071    ByteBuffer buffer = ByteBuffer.allocate(length);
072    buffer.put(getId());
073    buffer.put(length);
074    buffer.put(ack);
075    buffer.put(specific);
076    buffer.rewind();
077    return buffer;
078  }
079
080  protected abstract void parseSpecific(ByteBuffer buffer);
081
082  protected abstract byte[] serializeSpecific();
083}