You are viewing an old version of this page. View the current version.
Compare with Current
View Page History
« Previous
Version 3
Next »
package nl.wldelft.timeseriesparsers;
import nl.wldelft.util.DateUtils;
import nl.wldelft.util.IOUtils;
import nl.wldelft.util.io.BinaryParser;
import nl.wldelft.util.io.LittleEndianDataInputStream;
import nl.wldelft.util.timeseries.DefaultTimeSeriesHeader;
import nl.wldelft.util.timeseries.TimeSeriesContentHandler;
import org.apache.log4j.Logger;
import java.io.BufferedInputStream;
import java.io.IOException;
/**
* TimeSeries reader for Keller AG *.IDC files
*
*/
public class IdcTimeSeriesParser implements BinaryParser<TimeSeriesContentHandler> {
private static final Logger log = Logger.getLogger(IdcTimeSeriesParser.class);
// Constanten
private static final int DF_ID_FILE = 0;
private static final int DF_ID_DEVICE = 1;
private static final int DF_ID_DATA = 2;
private static final int DF_ID_UNITS = 3;
private static final int DF_ID_PROFILE = 4;
private static final int DF_ID_CONFIG = 5;
private static final int DF_ID_WL_CONVERTED = 6;
private static final int DF_ID_AIR_COMPENSATED = 7;
private static final int DF_ID_INFO = 8;
//
private LittleEndianDataInputStream is = null;
private TimeSeriesContentHandler contentHandler = null;
private int rawTimeZoneOffset;
/**
* Parse Keller AG *.idc bestand
*
* @param inputStream
* @param virtualFileName
* @param contentHandler
* @throws Exception
*/
@Override
public void parse(BufferedInputStream inputStream, String virtualFileName, TimeSeriesContentHandler contentHandler) throws Exception {
this.is = new LittleEndianDataInputStream(inputStream);
this.contentHandler = contentHandler;
this.rawTimeZoneOffset = contentHandler.getDefaultTimeZone().getRawOffset();
boolean abVersion0310 = false;
String locationId = "";
float[] userValArr = new float[12];
float installationDepth = 0f;
float heightOfWellhead = 0f;
float offset = 0f;
float waterDensity = 0f;
byte batteryCapacity = 0;
long startTime = Long.MIN_VALUE;
DefaultTimeSeriesHeader header = new DefaultTimeSeriesHeader();
DefaultTimeSeriesHeader headerEq = new DefaultTimeSeriesHeader();
// Continue to read lines while
// there are still some left to read
while (true) {
is.mark(1);
int nextByte = is.read();
if (nextByte == -1) break; // EOF
is.reset();
// Read block ID
short blockId = readBlock();
switch (blockId) {
case DF_ID_FILE:
// File Identification
String version = readString();
if (log.isDebugEnabled()) log.debug("version = " + version);
break;
case DF_ID_DEVICE:
// Device properties
int lw = this.is.readInt();
int w1 = lw / 65536;
int w2 = lw % 65536;
int klasse = w1 / 256;
int groep = w1 % 256;
int jaar = w2 / 256;
int week = w2 % 256;
if (jaar == 3) {
if (week >= 10) {
abVersion0310 = true;
}
}
if (jaar > 3) {
abVersion0310 = true;
}
int serialNumber = this.is.readInt();
boolean configuredAsWaterlevel = this.is.readBoolean();
locationId = readString();
String comment = readString();
if (log.isDebugEnabled()) {
log.debug("serial number = " + serialNumber);
log.debug("configured as waterlevel = " + configuredAsWaterlevel);
log.debug("comment = " + comment);
log.debug("location id = " + locationId);
}
break;
case DF_ID_DATA:
// Data records
int z = this.is.readInt();
for (int i = 0; i < z; i++) {
// datum 8 bytes double
// channel 1 byte
// 3 bytes skip
// value 4 bytes float
// lw 4 bytes int
// 4 bytes skip
// The date is stored as the number of days since 30 Dec 1899. Quite why it is not 31 Dec is not clear. 01 Jan 1900 has a days value of 2.
double doubleTime = is.readDouble();
long time = DateUtils.toTimeFromMicrosoftComDate(doubleTime);
// Bewaar lijst met tijden voor de reeks met inhangdiepte's
if (startTime == Long.MIN_VALUE) startTime = time;
contentHandler.setTime(new Long(time));
byte channel = this.is.readByte();
contentHandler.setTimeSeriesHeader(channel);
IOUtils.skipFully(is, 3);
float singleValue = this.is.readFloat();
contentHandler.setValue(singleValue);
contentHandler.applyCurrentFields();
int longValue = this.is.readInt();
// Skip 4 bytes
IOUtils.skipFully(is, 4);
}
break;
case DF_ID_UNITS:
boolean retval = parseUnits(locationId, header);
if (!retval){
log.error("Bestand bevat niet de juiste eenheden");
throw new Exception("Bestand bevat niet de juiste eenheden");
}
break;
case DF_ID_PROFILE:
// Read device profile
for (int i = 0; i < userValArr.length; i++) {
userValArr[i] = this.is.readFloat();
if (log.isDebugEnabled()) log.debug("userValArr " + userValArr[i]);
}
installationDepth = userValArr[2];
if (log.isDebugEnabled()) log.debug("installation depth " + installationDepth);
heightOfWellhead = userValArr[3];
if (log.isDebugEnabled()) log.debug("Height of wellhead above sea level " + heightOfWellhead);
offset = userValArr[4];
if (log.isDebugEnabled()) log.debug("Offset " + offset);
waterDensity = userValArr[5];
if (log.isDebugEnabled()) log.debug("Water density " + waterDensity);
short availableChannels = this.is.readShort();
if ((availableChannels & 2) == 2) {
float p1min = this.is.readFloat();
float p1max = this.is.readFloat();
if (log.isDebugEnabled()) log.debug("P1 min " + p1min);
if (log.isDebugEnabled()) log.debug("P1 max " + p1max);
}
if ((availableChannels & 4) == 4) {
float p2min = this.is.readFloat();
float p2max = this.is.readFloat();
if (log.isDebugEnabled()) log.debug("P2 min " + p2min);
if (log.isDebugEnabled()) log.debug("P2 max " + p2max);
}
if ((availableChannels & 8) == 8) {
float t1min = this.is.readFloat();
float t1max = this.is.readFloat();
if (log.isDebugEnabled()) log.debug("T1 min " + t1min);
if (log.isDebugEnabled()) log.debug("T1 max " + t1max);
}
if ((availableChannels & 16) == 16) {
float tob1min = this.is.readFloat();
float tob1max = this.is.readFloat();
if (log.isDebugEnabled()) log.debug("TOB1 min " + tob1min);
if (log.isDebugEnabled()) log.debug("TOB1 max " + tob1max);
}
if ((availableChannels & 32) == 32) {
float tob2min = this.is.readFloat();
float tob2max = this.is.readFloat();
if (log.isDebugEnabled()) log.debug("TOB2 min " + tob2min);
if (log.isDebugEnabled()) log.debug("TOB2 max " + tob2max);
}
break;
case DF_ID_CONFIG:
// Record configuration
int startDate = this.is.readInt();
int stopDate = this.is.readInt();
lw = this.is.readInt();
int recordedChannels = lw / 65536;
int recordModus = lw % 65536;
float trigger1 = this.is.readFloat();
float trigger2 = this.is.readFloat();
if (abVersion0310) {
int recFixCounter = this.is.readInt();
short recModCounter = this.is.readShort();
} else {
lw = this.is.readInt();
int recFixCounter = lw / 65536;
int tmp = lw % 65536;
short recModCounter = (short) tmp;
}
short sw = this.is.readShort();
int tmp = sw / 256;
short recModChannel = (short) tmp;
tmp = sw % 256;
short recSaveCounter = (short) tmp;
short recFastModCounter = this.is.readShort();
boolean recEndless = this.is.readBoolean();
break;
case DF_ID_WL_CONVERTED:
// Waterlevel converted
boolean convertedIntoWaterlevel = is.readBoolean();
break;
case DF_ID_AIR_COMPENSATED:
// Airpressure compensation
boolean airCompensated = is.readBoolean();
break;
case DF_ID_INFO:
// Additional information
batteryCapacity = this.is.readByte();
for (int i = 0; i < 10; i++) {
int reserve = this.is.readInt();
}
// Read CRC16 sum of the whole file
short crc16 = is.readShort();
break;
}
}
// Inhangdiepte
headerEq.setLocationId(locationId);
contentHandler.setTime(startTime);
headerEq.setParameterId("InstallationDepth");
headerEq.setUnit("m");
contentHandler.setTimeSeriesHeader(headerEq);
contentHandler.setValue(installationDepth);
contentHandler.applyCurrentFields();
headerEq.setParameterId("HeightOfWellhead");
headerEq.setUnit("m");
contentHandler.setTimeSeriesHeader(headerEq);
contentHandler.setValue(heightOfWellhead);
contentHandler.applyCurrentFields();
headerEq.setParameterId("Offset");
headerEq.setUnit("m");
contentHandler.setTimeSeriesHeader(headerEq);
contentHandler.setValue(offset);
contentHandler.applyCurrentFields();
headerEq.setParameterId("WaterDensity");
headerEq.setUnit("kg/m3");
contentHandler.setTimeSeriesHeader(headerEq);
contentHandler.setValue(waterDensity);
contentHandler.applyCurrentFields();
headerEq.setParameterId("BatteryCapacity");
headerEq.setUnit("%");
contentHandler.setTimeSeriesHeader(headerEq);
contentHandler.setValue(batteryCapacity);
contentHandler.applyCurrentFields();
}
/**
* Read block identification
* @return block identification
* @throws IOException
*/
private short readBlock() throws IOException {
short block = this.is.readShort();
short w1 = this.is.readShort();
short w2 = this.is.readShort();
int n = (65536 * w1) + w2;
return block;
}
/**
*
*
*
* @param locationId
* @param header
* @return
* @throws java.io.IOException
*/
private boolean parseUnits(
String locationId,
DefaultTimeSeriesHeader header) throws IOException {
boolean retval = true;
short availableChannels = this.is.readShort();
short amountOfUnits = this.is.readShort();
for (int i = 0; i < amountOfUnits; i++) {
// Kanaal
byte channel = this.is.readByte();
// Eenheid
byte[] bytes = new byte[7];
this.is.read(bytes, 0, 7);
String unit = new String(bytes, 1, bytes[0]);
if(unit.equalsIgnoreCase("m")){
retval = false;
}
header.setUnit(unit);
if (unit.contains("°C")) {
header.setUnit("deg C");
}
// Multiplier
float multiplier = this.is.readFloat();
// Offet
float offset = this.is.readFloat();
// Description
bytes = new byte[41];
this.is.read(bytes, 0, 41);
String description = new String(bytes, 1, bytes[0]);
IOUtils.skipFully(is, 3);
if (log.isDebugEnabled()) {
log.debug("channel " + channel);
log.debug("multiplier " + multiplier);
log.debug("offset " + offset);
log.debug("unit " + unit);
log.debug("description " + description);
}
header.setLocationId(locationId);
header.setParameterId(Byte.toString(channel));
contentHandler.createTimeSeriesHeaderAlias(channel, header);
}
return retval;
}
/**
* Read a string from file
* @return string from file
* @throws Exception
*/
private String readString() throws IOException {
String retval = "";
// lees lengte van de string
short length = this.is.readShort();
if (length > 0) {
// Create the byte array to hold the data
byte[] bytes = new byte[length];
int nob = this.is.read(bytes, 0, length);
if (nob == length) {
retval = new String(bytes);
}
}
return retval;
}
}