package edu.colostate.vchill.chill;
import edu.colostate.vchill.ChillDefines;
import edu.colostate.vchill.ScaleManager;
import edu.colostate.vchill.socket.SocketUtil;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
/**
* Data header
*
* @author Jochen Deyke
* @author jpont
* @version 2009-06-01
*/
public class ChillDataHeader extends ChillHeader {
private static final ScaleManager sm = ScaleManager.getInstance();
/**
* size (in bytes) of this header (including ChillHeaderHeader, but not including extraData)
*/
public static final int BYTE_SIZE = ChillHeaderHeader.BYTE_SIZE +
2 * ChillDefines.LONG_BYTE_SIZE + 9 * ChillDefines.INT_BYTE_SIZE;
/**
* Bit map of data types requested by client (ppi).
* See moment.h e.g. ZDR_MOM for definitions
*/
public long requestedData;
/**
* bit map as above for what fields are available from processor
*/
public long availableData;
/**
* Ant position at start of integration cycle.
* All angles scaled as indicated by angleScale in ChillHSKHeader.java
*/
public int startAz, startEl;
/**
* Ant position at end of integration cycle.
* All angles scaled as indicated by angleScale in ChillHSKHeader.java
*/
public int endAz, endEl;
/**
* number of gates in this ray
*/
public int numGates;
/**
* the range to the first data gate in millimeters
*/
public int startRange;
/**
* unix time word for (first txmit pulse in) this ray (seconds)
*/
public long dataTime;
/**
* aditional nanoseconds to first txmit pulse
*/
public int fractionalSecs;
/**
* ray number within this volume, starts at 1
*/
public int rayNumber;
public ChillDataHeader() {
super(new ChillHeaderHeader(ChillDefines.GEN_MOM_DATA, BYTE_SIZE));
super.extraData = new byte[0];
}
public ChillDataHeader(final ChillDataHeader other) {
super(new ChillHeaderHeader(other.header));
assert header.recordType == ChillDefines.GEN_MOM_DATA;
assert header.headerLength - ChillDataHeader.BYTE_SIZE >= 0;
this.requestedData = other.requestedData;
this.availableData = other.availableData;
this.startAz = other.startAz;
this.startEl = other.startEl;
this.endAz = other.endAz;
this.endEl = other.endEl;
this.numGates = other.numGates;
this.startRange = other.startRange;
this.dataTime = other.dataTime;
this.fractionalSecs = other.fractionalSecs;
this.rayNumber = other.rayNumber;
this.extraData = new byte[other.extraData.length];
for (int i = 0; i < this.extraData.length; ++i)
this.extraData[i] = other.extraData[i];
}
/**
* Constructs a header by reading initial values from a DataInput.
*
* @param in the DataInput to read initialization values from
*/
public ChillDataHeader(final DataInput in, final ChillHeaderHeader header) throws IOException {
super(header);
assert header.recordType == ChillDefines.GEN_MOM_DATA;
assert header.headerLength - ChillDataHeader.BYTE_SIZE >= 0;
this.requestedData = in.readLong();
this.availableData = in.readLong();
this.startAz = in.readInt();
this.startEl = in.readInt();
this.endAz = in.readInt();
this.endEl = in.readInt();
this.numGates = in.readInt();
this.startRange = in.readInt();
this.dataTime = SocketUtil.readUnsignedInt(in);
this.fractionalSecs = in.readInt();
this.rayNumber = in.readInt();
in.readFully(super.extraData = new byte[header.headerLength - ChillDataHeader.BYTE_SIZE]);
}
/**
* Writes this header to a DataOut
*
* @param out the DataOutput to write values to
*/
public void write(final DataOutput out) throws IOException {
assert header.recordType == ChillDefines.GEN_MOM_DATA;
assert header.headerLength == ChillDataHeader.BYTE_SIZE + extraData.length;
super.header.write(out);
out.writeLong(this.requestedData);
out.writeLong(this.availableData);
out.writeInt(this.startAz);
out.writeInt(this.startEl);
out.writeInt(this.endAz);
out.writeInt(this.endEl);
out.writeInt(this.numGates);
out.writeInt(this.startRange);
SocketUtil.writeUnsignedInt(this.dataTime, out);
out.writeInt(this.fractionalSecs);
out.writeInt(this.rayNumber);
out.write(this.extraData);
}
public ArrayList<String> calculateTypes() {
long available = this.requestedData & this.availableData;
int numAvailableFields = Long.bitCount(available);
ArrayList<String> types = new ArrayList<String>(numAvailableFields);
for (int i = 0; i < numAvailableFields; i++) {
/* Get the bit position of the first available field. */
int fieldNumber = Long.numberOfTrailingZeros(available);
/* Add the field to the list if the field header exists. */
ChillMomentFieldScale scale = sm.getScale(fieldNumber);
if (scale != null) {
types.add(scale.fieldName);
} else {
/*
* Just because we don't know about the field, VCHILL
* still needs to know how many fields to read in so
* add null to increase the size.
*/
types.add(null);
}
/* Remove this field bit from the mask. */
available ^= (1l << fieldNumber);
}
return types;
}
}