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}