package org.yamcs; import java.io.BufferedOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicInteger; import org.yamcs.archive.PacketWithTime; import org.yamcs.utils.GpsCcsdsTime; import org.yamcs.utils.StringConverter; import org.yamcs.utils.TimeEncoding; import org.yamcs.xtce.SequenceContainer; import com.google.common.util.concurrent.AbstractService; /** * Generates packets according to the refmdb database * @author nm * */ public class RefMdbPacketGenerator extends AbstractService implements TmPacketProvider { TmProcessor tmProcessor; public final int headerLength=16; public final int pkt1Length=headerLength+3; public final int pkt1_1Length=pkt1Length+56; public final int pkt1_2Length=pkt1Length+16; public final int pkt1_3Length=pkt1Length+100; public final int pkt1_4Length=pkt1Length+300; public final int pkt1_5Length=pkt1Length+50; public final int pkt1_6Length=pkt1Length+4; public final int pkt1_7Length=pkt1Length+6; public final int pkt1_8Length=pkt1Length+6; public final int pkt1_9Length=pkt1Length+1; public final int pkt1_10Length=pkt1Length+8; public final int pkt1_11Length=pkt1Length+4; public final int pkt4Length=headerLength+4; public final int pkt2Length=8; public final int pkt1_ListLength=pkt1Length; public final int pkt1_AndLength=pkt1Length; public final int pkt1_OrLength=pkt1Length; public final int pkt1_And_OrLength=pkt1Length; public final int contVerifCmdAck_Length = headerLength+7; public final int algVerifCmdAck_Length = headerLength+9; //raw values of parameters public volatile short pIntegerPara1_1=5; public volatile byte pIntegerPara1_1_1=20; public volatile short pFloatPara1_1_2=1000; public volatile float pFloatPara1_1_3=2; public volatile byte pEnumerationPara1_1_4=0; public volatile String pStringPara1_1_5="cucu"; public volatile int pIntegerPara1_1_6=236; public volatile byte pIntegerPara1_1_7=34; public volatile long pIntegerPara1_1_8=5084265585L; public volatile int pIntegerPara1_11_1=0xAFFFFFFE; // a uint32 stored in signed java int public volatile long pIntegerPara1_11_1_unsigned_value=2952790014L; // the equivalent unsigned value public volatile float pFloatPara1_20_1 = (float)(Math.PI/2); public volatile byte pLEIntegerPara1_2_1 = 13; public volatile short pLEIntegerPara1_2_2 = 1300; public volatile int pLEIntegerPara1_2_3 = 130000; public volatile short pLEFloatPara1_2_1 = 300; public volatile float pLEFloatPara1_2_2 = 2.7182f; static public final String pFixedStringPara1_3_1 = "Ab"; // 16 bits static public final String pFixedStringPara1_3_2 = "A"; // 8 bits static public final String pTerminatedStringPara1_3_3 = "Abcdef"; // Null terminated static public final String pTerminatedStringPara1_3_4 = "Abcdef"; // Comma terminated static public final String pPrependedSizeStringPara1_3_5 = "Abcdefghijklmnopqrstuvwxyz"; // First 16 bits (2 bytes) set size in bits of size tag static public final String pPrependedSizeStringPara1_3_6 = "Abcdef"; // First 8 bits (1 byte) set size in bits of size tag static public final String pFixedStringPara1_3_7="Abcdefghijklmnop"; // 128 bits // Get floats from strings public String pStringFloatFSPara1_4_1="1.34"; // Fixed size 32 bit public String pStringFloatTSCPara1_4_2="0.0000001"; // Comma terminated, leading zeros and calibrated static public final String pStringFloatTSSCPara1_4_3="0.12"; // Semi-colon terminated, leading zero static public final String pStringFloatFSBPara1_4_4="1.34567890123456"; // 128 bit string static public final String pStringFloatPSPara1_4_5="1.345678"; // Prepended size string, first 8 bits (1 byte) set size in bits of size tag // Get integers from strings static public final String pStringIntFixedPara1_5_1="120"; // Fixed size, 24 bits public String pStringIntTermPara1_5_2="12"; // Comma terminated static public final String pStringIntTermPara1_5_3="12045"; // Semi-colon terminated static public final String pStringIntPrePara1_5_4="1204507"; // Prepended size (16 bits) static public final String pStringIntStrPara1_5_5="123406789"; // string //Get enumerations from strings public String pStringEnumPara1_12_1="1"; static public final int pIntegerPara2_1 = 123; static public final int pIntegerPara2_2 = 25; Map<Integer, AtomicInteger> seqCount=new HashMap<Integer, AtomicInteger>(); private long generationTime = TimeEncoding.INVALID_INSTANT; /** * Constructor called when RefMdbPacketGenerator is declared in tmProviderList in yamcs.instance.yaml */ public RefMdbPacketGenerator(String instance, String name, String spec) { } public RefMdbPacketGenerator() { } @Override public void init(Processor proc, TmProcessor tmProcessor) { this.tmProcessor=tmProcessor; } public ByteBuffer generate_PKT1_1() { ByteBuffer bb=ByteBuffer.allocate(pkt1_1Length); fill_PKT1_1(bb); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1_2() { ByteBuffer bb=ByteBuffer.allocate(pkt1_2Length); fill_PKT1_2(bb); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1_3() { ByteBuffer bb=ByteBuffer.allocate(pkt1_3Length); fill_PKT1_3(bb); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT14() { ByteBuffer bb=ByteBuffer.allocate(pkt1_4Length); fill_PKT1_4(bb); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1_5() { ByteBuffer bb=ByteBuffer.allocate(pkt1_5Length); fill_PKT1_5(bb); sendToTmProcessor(bb); return bb; } /** * Generate a packet with configurable content */ public ByteBuffer generate_PKT1_6(int pIntegerPara16_1, int pIntegerPara16_2) { return generate_PKT1_6(pIntegerPara16_1, pIntegerPara16_2, TimeEncoding.getWallclockTime(), TimeEncoding.getWallclockTime()); } /** * Generate a packet with configurable content */ public ByteBuffer generate_PKT1_6(int pIntegerPara16_1, int pIntegerPara16_2, long rectime, long gentime) { ByteBuffer bb=ByteBuffer.allocate(pkt1_6Length); fill_PKT1_6(bb, pIntegerPara16_1, pIntegerPara16_2); sendToTmProcessor(bb, rectime, gentime); return bb; } public ByteBuffer generate_PKT1_7() { ByteBuffer bb=ByteBuffer.allocate(pkt1_7Length); fill_PKT1_7(bb); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1_8(int pIntegerPara18_1, int pIntegerPara18_2) { ByteBuffer bb=ByteBuffer.allocate(pkt1_8Length); fill_PKT1_8(bb, pIntegerPara18_1, pIntegerPara18_2); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1_9() { ByteBuffer bb=ByteBuffer.allocate(pkt1_9Length); fill_PKT1_9(bb); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1_10(int pIntegerPara1_10_1, int pEnumerationPara1_10_2, float pFloatPara1_10_3) { ByteBuffer bb=ByteBuffer.allocate(pkt1_10Length); fill_PKT1_10(bb, pIntegerPara1_10_1, pEnumerationPara1_10_2, pFloatPara1_10_3); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1_11() { ByteBuffer bb=ByteBuffer.allocate(pkt1_11Length); fill_PKT1_11(bb); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1_12() { ByteBuffer bb=ByteBuffer.allocate(pkt1Length + pStringEnumPara1_12_1.length()+1); fill_PKT1_12(bb); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT4() { ByteBuffer bb=ByteBuffer.allocate(pkt4Length); fill_PKT4(bb); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT2() { ByteBuffer bb=ByteBuffer.allocate(pkt2Length); fill_PKT2(bb); sendToTmProcessor(bb); return bb; } // Packets to test the boolean inheritance condition public ByteBuffer generate_PKT1_List(){ ByteBuffer bb = ByteBuffer.allocate(pkt1_ListLength); fill_PKT1(bb, 1, 13, (short)2); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1_AND(){ ByteBuffer bb = ByteBuffer.allocate(pkt1_ListLength); fill_PKT1(bb, 2, 13, (short)3); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1_OR_1(){ ByteBuffer bb = ByteBuffer.allocate(pkt1_ListLength); fill_PKT1(bb, 1, 14, (short)2); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1_AND_OR_1(){ ByteBuffer bb = ByteBuffer.allocate(pkt1_ListLength); fill_PKT1(bb, 1, 15, (short)1); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1_AND_OR_2(){ ByteBuffer bb = ByteBuffer.allocate(pkt1_ListLength); fill_PKT1(bb, 14, 0, (short)15); sendToTmProcessor(bb); return bb; } public ByteBuffer generate_PKT1(int integerPara1_1, int packetType, short integerPara1_2 ){ ByteBuffer bb = ByteBuffer.allocate(pkt1_ListLength); fill_PKT1(bb, integerPara1_1, packetType, integerPara1_2); sendToTmProcessor(bb); return bb; } public ByteBuffer generateContVerifCmdAck(short cmdId, byte stage, int result) { ByteBuffer bb=ByteBuffer.allocate(contVerifCmdAck_Length); fill_CcsdsHeader(bb, 101, 1000); bb.position(headerLength); bb.putShort(cmdId); bb.put(stage); bb.putInt(result); sendToTmProcessor(bb); return bb; } public ByteBuffer generateAlgVerifCmdAck(short cmdId, short packetSeq, byte stage, int result) { ByteBuffer bb=ByteBuffer.allocate(algVerifCmdAck_Length); fill_CcsdsHeader(bb, 101, 2000); bb.position(headerLength); bb.putShort(cmdId); bb.putShort(packetSeq); bb.put(stage); bb.putInt(result); sendToTmProcessor(bb); return bb; } /* Dynamic sized packet. Test packet contains: ccsds_header (headerLength bits) IntegerPara1_1 = 2 (4 bits) IntegerPara1_2 = 3 (16 bits) IntegerPara1_2 = 4 (16 bits) block_para1 = 5 (8 bits) block_para2 = 6 (8 bits) block_para1 = 7 (8 bits) block_para2 = 8 (8 bits) block_para1 = 9 (8 bits) block_para2 = 10 (8 bits) block_para3 = 11 (8 bits) block_para4 = 12 (8 bits) block_para3 = 13 (8 bits) block_para4 = 14 (8 bits) */ public ByteBuffer generate_PKT3() { int pktLength = headerLength + 1 + 2*2 + 11; ByteBuffer bb=ByteBuffer.allocate(pktLength); fill_PKT3(bb); sendToTmProcessor(bb); return bb; } /** * set the generation time used to send the packets. * If TimeEncoding.INVALID_INSTANT is used, the current time will be sent * @param genTime */ public void setGenerationTime(long genTime) { this.generationTime = genTime; } private void fill_CcsdsHeader(ByteBuffer bb, int apid, int packetId) { short xs; //Primary header: // version(3bits) type(1bit) secondary header flag(1bit) apid(11 bits) xs=(short)((3<<11)|apid); bb.putShort(0, xs); AtomicInteger a=seqCount.get(apid); if(a==null) { a=new AtomicInteger(0); seqCount.put(apid,a); } //Seq Flags (2 bits) Seq Count(14 bits) xs=(short) ((3<<14)|a.getAndIncrement()); bb.putShort(2, xs); //packet length (16 bits). bb.putShort(4,(short)(bb.capacity()-7)); //Secondary header: //coarse time(32 bits) GpsCcsdsTime t=TimeEncoding.getCurrentGpsTime(); bb.putInt(6, t.coarseTime); //fine time(8 bits) timeID(2bits) checkword(1 bit) spare(1 bit) pktType(4 bits) // xs=(short)((shTimeId<<6)|(shChecksumIndicator<<5)|shPacketType); bb.put(10, t.fineTime); //packetId(32 bits) bb.putInt(12, packetId); } private void fill_PKT1(ByteBuffer bb, int packetType) { fill_CcsdsHeader(bb, 995, 318813007); bb.put(headerLength, (byte)((pIntegerPara1_1<<4)+packetType)); } private void fill_PKT1(ByteBuffer bb, int integerPara1_1, int packetType, short integerPara1_2) { fill_CcsdsHeader(bb, 995, 318813007); bb.put(headerLength, (byte)((integerPara1_1<<4)+packetType)); bb.putShort(headerLength + 1, integerPara1_2); } private void fill_PKT1_1(ByteBuffer bb) { fill_PKT1(bb, 1); int offset=pkt1Length; bb.position(offset); bb.put(pIntegerPara1_1_1); bb.putShort(pFloatPara1_1_2); bb.putFloat(pFloatPara1_1_3); bb.put(pEnumerationPara1_1_4); bb.put((byte)(pIntegerPara1_1_6>>16)); bb.putShort((short)(pIntegerPara1_1_6&0xFFFF)); bb.put(pIntegerPara1_1_7); bb.putShort((short)(pIntegerPara1_1_8>>32)); bb.putInt((int)pIntegerPara1_1_8&0xFFFFFFFF); byte[] b=new byte[10]; System.arraycopy(pStringPara1_1_5.getBytes(), 0, b, 0, pStringPara1_1_5.getBytes().length); bb.put(b); } private void fill_PKT1_2(ByteBuffer bb) { fill_PKT1(bb, 2); bb.position(pkt1Length); bb.order(ByteOrder.LITTLE_ENDIAN); bb.put(pLEIntegerPara1_2_1); bb.putShort(pLEIntegerPara1_2_2); bb.putInt(pLEIntegerPara1_2_3); bb.putShort(pLEFloatPara1_2_1); bb.putFloat(pLEFloatPara1_2_2); } private void fill_PKT1_3(ByteBuffer bb) { fill_PKT1(bb, 3); int offset=pkt1Length; bb.position(offset); putFixedStringParam(bb, pFixedStringPara1_3_1, 16); putFixedStringParam(bb, pFixedStringPara1_3_2, 8); putTerminatedStringParam(bb, pTerminatedStringPara1_3_3, (byte)0); putTerminatedStringParam(bb, pTerminatedStringPara1_3_4, (byte)','); putPrependedSizeStringParam(bb, pPrependedSizeStringPara1_3_5, 16); putPrependedSizeStringParam(bb, pPrependedSizeStringPara1_3_6, 8); putFixedStringParam(bb, pFixedStringPara1_3_7, 128); } private void fill_PKT1_4(ByteBuffer bb) { fill_PKT1(bb, 4); int offset=pkt1Length; bb.position(offset); // Floats in strings putFixedStringParam(bb, pStringFloatFSPara1_4_1, 32); putTerminatedStringParam(bb, pStringFloatTSCPara1_4_2, (byte)','); putTerminatedStringParam(bb, pStringFloatTSSCPara1_4_3, (byte)';'); putTerminatedStringParam(bb, pStringFloatTSSCPara1_4_3, (byte)';'); putPrependedSizeStringParam(bb, pStringFloatPSPara1_4_5, 8); putFixedStringParam(bb, pStringFloatFSBPara1_4_4, 128); } private void fill_PKT1_5(ByteBuffer bb) { fill_PKT1(bb, 5); int offset=pkt1Length; bb.position(offset); // Integers in strings putFixedStringParam(bb, pStringIntFixedPara1_5_1, 24); putTerminatedStringParam(bb, pStringIntTermPara1_5_2, (byte)','); putTerminatedStringParam(bb, pStringIntTermPara1_5_3, (byte)';'); putPrependedSizeStringParam(bb, pStringIntPrePara1_5_4, 16); // Straight string is null terminated putTerminatedStringParam(bb, pStringIntStrPara1_5_5, (byte)0); } private void fill_PKT4(ByteBuffer bb) { fill_CcsdsHeader(bb, 995, 4); bb.position(headerLength); bb.putFloat(pFloatPara1_20_1); } private void fill_PKT2(ByteBuffer bb) { bb.position(4); bb.putShort((short)(pIntegerPara2_1&0xFFFF)); bb.putShort((short)(pIntegerPara2_2&0xFFFF)); } private void fill_PKT1_6(ByteBuffer bb, int pIntegerPara16_1, int pIntegerPara16_2) { fill_PKT1(bb, 6); int offset=pkt1Length; bb.position(offset); bb.putShort((short)(pIntegerPara16_1&0xFFFF)); bb.putShort((short)(pIntegerPara16_2&0xFFFF)); } private void fill_PKT1_7(ByteBuffer bb) { fill_PKT1(bb, 7); int offset=pkt1Length; bb.position(offset); // 16-bit signed integer (in sign-magnitude) bb.put(StringConverter.hexStringToArray("BA50")); // 6 (000110), filler (000), -6 (100110) (sign-magnitude) bb.put(StringConverter.hexStringToArray("1846")); // 6 (000110), filler (000), -6 (111010) (2's complement) bb.put(StringConverter.hexStringToArray("187A")); } private void fill_PKT1_8(ByteBuffer bb, int pIntegerPara18_1, int pIntegerPara18_2) { fill_PKT1(bb, 8); int offset=pkt1Length; bb.position(offset); bb.putShort((short)(pIntegerPara18_1&0xFFFF)); bb.putInt(pIntegerPara18_2); } private void fill_PKT1_9(ByteBuffer bb) { fill_PKT1(bb, 9); int offset=pkt1Length; bb.position(offset); bb.put((byte) 0xA1); } private void fill_PKT1_10(ByteBuffer bb, int pIntegerPara1_10_1, int pEnumerationPara1_10_2, float pFloatPara1_10_3) { fill_PKT1(bb, 10); int offset=pkt1Length; bb.position(offset); bb.putShort((short) pIntegerPara1_10_1); bb.put((byte) pEnumerationPara1_10_2); bb.put((byte) 0); bb.putFloat(pFloatPara1_10_3); } private void fill_PKT1_11(ByteBuffer bb) { fill_PKT1(bb, 11); int offset=pkt1Length; bb.position(offset); bb.putInt(pIntegerPara1_11_1); } private void fill_PKT1_12(ByteBuffer bb) { fill_PKT1(bb, 12); int offset=pkt1Length; bb.position(offset); putTerminatedStringParam(bb, pStringEnumPara1_12_1, (byte)';'); } private void fill_PKT3(ByteBuffer bb) { fill_CcsdsHeader(bb, 995, 318813009); bb.position(headerLength); bb.put((byte) (2 << 4)); // IntegerPara1_1 = 2 (4 bits) bb.put((byte)0); // IntegerPara1_2 = 3 bb.put((byte)3); // bb.put((byte)0); // IntegerPara1_2 = 4 bb.put((byte)4); // bb.put((byte)5); // block_para1 = 5 bb.put((byte)6); // block_para2 = 6 bb.put((byte)61); // block_para2_1 = 61 bb.put((byte)7); // block_para1 = 7 bb.put((byte)8); // block_para2 = 8 bb.put((byte)9); // block_para1 = 9 bb.put((byte)10); // block_para2 = 10 bb.put((byte)11); // block_para3 = 11 bb.put((byte)12); // block_para4 = 12 bb.put((byte)13); // block_para3 = 13 bb.put((byte)14); // block_para4 = 14 } private void putFixedStringParam( ByteBuffer bb, String value, int bits ) { int baSize = bits / 8; if( bits == -1 ) { baSize = value.getBytes().length; } byte[] ba=new byte[ baSize ]; System.arraycopy(value.getBytes(), 0, ba, 0, value.getBytes().length); bb.put( ba ); //System.out.println( String.format( "- put FixedString '%s' length %d bits in %d bits", value, value.getBytes().length*8, baSize*8 ) ); } private void putTerminatedStringParam( ByteBuffer bb, String value, byte terminator ) { byte[] ba=new byte[ value.getBytes().length+1]; System.arraycopy(value.getBytes(), 0, ba, 0, value.getBytes().length); ba[ba.length-1] = terminator; bb.put( ba ); /* if( terminator == 0 ) { System.out.println( String.format( "- put TerminatedString '%s' length %d bits (%d bytes) with terminator null", value, value.getBytes().length*8, value.getBytes().length ) ); } else { System.out.println( String.format( "- put TerminatedString '%s' length %d bits (%d bytes) with terminator '%c'", value, value.getBytes().length*8, value.getBytes().length, terminator ) ); } */ } private void putPrependedSizeStringParam( ByteBuffer bb, String value, int tagSizeInBits ) { if( tagSizeInBits <= 8 ) { bb.put( ((byte)(value.getBytes().length)) ); } else { bb.putShort( ((short)(value.getBytes().length)) ); } byte[] ba=new byte[ value.getBytes().length ]; System.arraycopy(value.getBytes(), 0, ba, 0, value.getBytes().length); bb.put( ba ); //System.out.println( String.format("- put PrependedSizeString '%s' with leading %d bits filled with number %d to specify the number of bytes the string uses.",value,tagSizeInBits,value.getBytes().length) ); } private void sendToTmProcessor(ByteBuffer bb) { long gentime = generationTime; if(gentime==TimeEncoding.INVALID_INSTANT) { gentime = TimeEncoding.getWallclockTime(); } sendToTmProcessor(bb, TimeEncoding.getWallclockTime(), gentime); } private void sendToTmProcessor(ByteBuffer bb, long rectime, long gentime) { if(tmProcessor!=null) { tmProcessor.processPacket(new PacketWithTime(rectime, gentime, bb.array())); } } @Override public boolean isArchiveReplay() { return false; } public static void main(String[] args) throws FileNotFoundException, InterruptedException, ConfigurationException { String f="/tmp/refmdb.pktfile"; RefMdbPacketGenerator mdbgen=new RefMdbPacketGenerator(); YConfiguration.setup(); final BufferedOutputStream os=new BufferedOutputStream(new FileOutputStream(f)); final Semaphore s=new Semaphore(0); final AtomicInteger count=new AtomicInteger(0); mdbgen.init(null, new TmProcessor() { @Override public void processPacket(PacketWithTime pwrt) { try { os.write(pwrt.getPacket()); count.incrementAndGet(); os.close(); } catch (IOException e) { e.printStackTrace(); } s.release(); } @Override public void finished() { // TODO Auto-generated method stub } @Override public void processPacket(PacketWithTime pwrt, SequenceContainer def) { processPacket(pwrt); } }); mdbgen.startAsync(); s.acquire(); mdbgen.stopAsync(); } @Override protected void doStart() { notifyStarted(); } @Override protected void doStop() { notifyStopped(); } }