package org.yamcs.utils;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Calendar;
public class PacketFormatter {
private boolean withoutCcsds = false;
private boolean withPacts = false, withArch = false;
private boolean hex = false;
private OutputStream out;
private boolean onlyHeader;
public PacketFormatter(OutputStream out) {
this.out=out;
}
public void writePacket(CcsdsPacket c) throws IOException {
ByteBuffer bb=c.getByteBuffer();
if(withoutCcsds) bb.position(16);
else bb.position(0);
if(onlyHeader) {
System.out.println("APID: "+CcsdsPacket.getAPID(bb)+", packetId: "+c.getPacketID()+" seqCount: "+CcsdsPacket.getSequenceCount(bb)+
", gentime: "+TimeEncoding.toCombinedFormat(CcsdsPacket.getInstant(bb)));
} else if(hex) {
out.write(("apid: "+c.getAPID()+", seqCount: "+c.getSequenceCount()+", packetid: "+c.getPacketID()+"\n").getBytes());
out.write(("time: "+TimeEncoding.toOrdinalDateTime(c.getInstant())+"\n").getBytes());
}
if(withPacts) { //add a fake pacts header
ByteBuffer pactsMsgHdr = ByteBuffer.allocate(32);
CcsdsPacket ccsds = new CcsdsPacket(bb);
pactsMsgHdr.putInt(bb.limit() - 16); // without CCSDS header
pactsMsgHdr.putInt(ccsds.getAPID() | 0x1000); // this is a PAYLOAD packet (not a SYSTEM packet)
pactsMsgHdr.putInt(ccsds.getPacketID());
pactsMsgHdr.putInt((int)ccsds.getCoarseTime());
pactsMsgHdr.putInt(ccsds.getFineTime());
pactsMsgHdr.rewind();
if(hex) {
while(pactsMsgHdr.position()<pactsMsgHdr.capacity()) {
out.write(String.format("%04x ",0xFFFF&pactsMsgHdr.getShort()).getBytes());
if(pactsMsgHdr.position()%16==0) out.write("\n".getBytes());
}
out.write("\n".getBytes());
} else {
out.write(pactsMsgHdr.array());
}
} else if (withArch) {
// add an HRDP PathTM archive header (mutually exclusive with Pacts header)
long now = Calendar.getInstance().getTimeInMillis();
if (hex) {
// TODO, or unnecessary. Archive headers are useful only when binary.
} else {
ByteBuffer arcHdr = ByteBuffer.allocate(10).order(ByteOrder.LITTLE_ENDIAN);
arcHdr.putInt(bb.limit() + 6); // 6 = rest of archive header
arcHdr.put((byte)9); // constant
arcHdr.order(ByteOrder.BIG_ENDIAN);
arcHdr.putInt((int)(now / 1000 - 315964800)); // coarse time in GPS
arcHdr.put((byte)((now % 1000) * 256 / 1000)); // fine time
out.write(arcHdr.array());
}
}
if(hex) {
while(bb.position()<bb.capacity()) {
out.write(String.format("%04x ",0xFFFF&bb.getShort()).getBytes());
if(bb.position()%16==0) out.write("\n".getBytes());
}
out.write("\n".getBytes());
} else {
if(bb.hasArray()){
out.write(bb.array(),bb.position(),bb.remaining());
} else {
byte[] b=new byte[bb.capacity()];
bb.get(b);
out.write(b);
}
}
}
public void setOnlyHeader(boolean b) {
this.onlyHeader=b;
}
public void setHex(boolean hex) {
this.hex = hex;
}
public void setWithoutCcsds(boolean withoutCcsds) {
this.withoutCcsds = withoutCcsds;
}
public void setWithPacts(boolean withPacts) {
this.withPacts = withPacts;
}
public void setWithArch(boolean withArch) {
this.withArch = withArch;
}
public void close() throws IOException {
out.close();
}
}