org.xtce.toolkit.XTCEItemValue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xtcetools Show documentation
Show all versions of xtcetools Show documentation
This project contains software to support the Object Management Group (OMG) Space Domain Task Force (SDTF) maintained XML Telemetry and Command Exchange (XTCE) specification.
/* Copyright 2015 David Overeem ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.xtce.toolkit;
import org.xtce.math.MilStd1750A;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import org.omg.space.xtce.AbsoluteTimeDataType;
import org.omg.space.xtce.BooleanDataType;
import org.omg.space.xtce.CalibratorType;
import org.omg.space.xtce.NameDescriptionType;
import org.omg.space.xtce.ValueEnumerationType;
import org.xtce.math.Calibration;
import org.xtce.math.MathOperationCalibration;
import org.xtce.math.PolynomialCalibration;
import org.xtce.math.SplineCalibration;
import org.xtce.toolkit.XTCETypedObject.EngineeringType;
import org.xtce.toolkit.XTCETypedObject.RawType;
/** This class captures the attributes needed to encode or decode a raw value
* to or from an engineering value and provides public methods to do these
* tasks from the caller's application.
*
* The encode method is for converting an EU value provided to a raw value.
* The decode method does the opposite, which converts a raw value back to an
* EU value. Telemetry typically uses decode on the ground and Telecommanding
* typically uses encode on the ground, with the reverse of both happening on
* the satellite side.
*
* The implementation of this class might seem a little strange or less than
* efficient because it is extended by platform specific classes for other use
* cases that overload the population of the attributes such that it can be
* used for specific cots products. Those extended implementations are not
* included in this toolkit.
*
* @author David Overeem
*
*/
public class XTCEItemValue {
/** Constructor
*
* @param item XTCETypedObject containing the Parameter or Argument
* that is being encoded/decoded.
*
*/
public XTCEItemValue( final XTCETypedObject item ) {
// first gather the general attributes that are common
itemName_ = item.getName();
euTypeName_ = item.getEngineeringType();
rawTypeName_ = item.getRawType();
rawBitOrder_ = item.getRawBitOrder();
itemObj_ = item;
// gather the Type Reference, for which we cannot proceed further
// unless exists
NameDescriptionType typeObj = item.getTypeReference();
if ( typeObj == null ) {
warn( itemName_ + " " + // NOI18N
XTCEFunctions.getText( "error_encdec_notype" ) ); // NOI18N
validObject_ = false;
return;
}
// gather the raw encoding size, which may not be appropriate
try {
rawSizeInBits_ = Integer.parseInt( item.getRawSizeInBits() );
validObject_ = true;
} catch ( NumberFormatException ex ) {
warn( itemName_ + " " + // NOI18N
XTCEFunctions.getText( "error_encdec_norawsize" ) + // NOI18N
" '" + rawSizeInBits_ + "'" ); // NOI18N
validObject_ = false;
}
// get the registered time handler if one exists
if ( euTypeName_ == EngineeringType.TIME ) {
try {
AbsoluteTimeDataType timeXml =
(AbsoluteTimeDataType)itemObj_.getTypeReference();
timeHandler_ =
XTCEFunctions.getAbsoluteTimeHandler( timeXml );
} catch ( XTCEDatabaseException ex ) {
warn( itemName_ + " " + ex.getLocalizedMessage() ); // NOI18N
validObject_ = false;
return;
}
}
// gather the extended attributes that are needed for specific types
setValidRangeAttributes( item );
setEnumerationList( item );
setDefaultCalibrator( item );
}
/** Constructor
*
* @param item XTCETypedObject containing the Parameter or Argument
* that is being encoded/decoded.
*
* @param calibrator CalibratorType containing the contextually accurate
* calibrator for this item value evaluation.
*
*/
public XTCEItemValue( final XTCETypedObject item,
final CalibratorType calibrator ) {
this( item );
defCal_ = calibrator;
}
/** Retrieves the item name of the Parameter or Argument that is the basis
* for this item value encode()/decode() object.
*
* @return String containing the name used when this object was
* constructed.
*
*/
public final String getItemName() {
return itemName_;
}
/** Retrieves the validity flag from this item value encode/decode.
*
* @return boolean indicating if the encode/decode can be performed. If
* this is false, the encode/decode functions will throw an exception.
*
*/
public final boolean isValid() {
return validObject_;
}
/** Retrieve the list of warnings that have accumulated since this object
* was created or since the caller last cleared the warnings list.
*
* @see #clearWarnings()
*
* @return List of String containing the warning messages.
*
*/
public final List getWarnings() {
if ( warnings_ == null ) {
return new ArrayList<>();
}
return warnings_;
}
/** Clears the list of warning messages for this object, which can be
* useful if multiple raw or engineering values need to be generated, so
* that the list does not include previous issues.
*
*/
public final void clearWarnings() {
if ( warnings_ != null ) {
warnings_.clear();
}
}
/** Retrieve the Calibrated/Engineering value of this typed object when
* given the raw binary value.
*
* This method is a shortcut to calling both the getUncalibratedFromRaw()
* and getCalibratedFromUncalibrated() functions. Those functions contain
* additional details for the reader concerning the nature of the data
* and what is being performed.
*
* The user must interrogate the getWarnings() method to ensure that this
* function did not encounter any problems during conversion. In the
* event that warnings happened, then the return value cannot be used.
*
* @param rawValue BitSet containing the raw binary value that would
* be encoded on the wire or bitfield. The raw binary is always expected
* to be in the order read from the stream.
*
* @return String containing the proper Calibrated/Engineering
* representation of the raw encoded value provided by the caller.
*
*/
public String decode( final BitSet rawValue ) {
String uncalValue = getUncalibratedFromRaw( rawValue );
if ( warnings_ != null && warnings_.isEmpty() == false ) {
return "";
} else {
return getCalibratedFromUncalibrated( uncalValue );
}
}
/** Retrieve the uncalibrated value of this typed object item when given
* the raw binary value.
*
* The raw value is provided as a Java BitSet to account for an
* arbitrary size of the raw value binary. The output of this function
* takes into account the encoding type to interpret the raw binary in the
* proper type and alignment.
*
* @param rawValue BitSet containing the raw binary value that would
* be encoded on the wire or bitfield. The raw binary is always expected
* to be in the order read from the stream.
*
* @return String containing the proper uncalibrated representation of the
* raw encoded value provided by the caller.
*
*/
public String getUncalibratedFromRaw( final BitSet rawValue ) {
clearWarnings();
if ( rawBitOrder_.equals( "mostSignificantBitFirst" ) == false ) { // NOI18N
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawbitorder" ) + // NOI18N
": '" + // NOI18N
rawBitOrder_ +
"'" ); // NOI18N
return ""; // NOI18N
}
if ( euTypeName_ == EngineeringType.TIME ) {
if ( timeHandler_ != null ) {
return timeHandler_.getUncalibratedFromRaw( rawValue );
} else {
return "0x00"; // NOI18N
}
}
BigInteger numericValue = bitSetToNumber( rawValue );
switch ( rawTypeName_ ) {
case unsigned:
isIntegerRawValueReasonable( numericValue );
return numericValue.toString();
case signMagnitude: {
BigInteger halfValue = BigInteger.valueOf( 2 ).pow( rawSizeInBits_ - 1 );
if ( numericValue.compareTo( halfValue ) >= 0 ) {
numericValue = numericValue.subtract( halfValue ).negate();
}
isIntegerRawValueReasonable( numericValue );
return numericValue.toString();
}
case twosComplement: {
BigInteger halfValue = BigInteger.valueOf( 2 ).pow( rawSizeInBits_ - 1 );
BigInteger fullValue = BigInteger.valueOf( 2 ).pow( rawSizeInBits_ );
if ( numericValue.compareTo( halfValue ) >= 0 ) {
numericValue = numericValue.subtract( fullValue );
}
isIntegerRawValueReasonable( numericValue );
return numericValue.toString();
}
case onesComplement: {
BigInteger halfValue = BigInteger.valueOf( 2 ).pow( rawSizeInBits_ - 1 );
BigInteger fullValue = BigInteger.valueOf( 2 ).pow( rawSizeInBits_ );
if ( numericValue.compareTo( halfValue ) >= 0 ) {
numericValue = numericValue.subtract( fullValue ).add( BigInteger.ONE );
}
isIntegerRawValueReasonable( numericValue );
return numericValue.toString();
}
case IEEE754_1985:
if ( rawSizeInBits_ == 32 ) {
Float floatValue = Float.intBitsToFloat( numericValue.intValue() );
isFloatRawValueReasonable( floatValue );
return floatValue.toString();
} else if ( rawSizeInBits_ == 64 ) {
Double doubleValue = Double.longBitsToDouble( numericValue.longValue() );
isFloatRawValueReasonable( doubleValue );
return doubleValue.toString();
} else if ( rawSizeInBits_ == 128 ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawtypenotsupported" ) + // NOI18N
": " + // NOI18N
rawTypeName_ +
" (" + // NOI18N
Integer.toString( rawSizeInBits_ ) +
" " + // NOI18N
XTCEFunctions.getText( "general_bits" ) + // NOI18N
")" ); // NOI18N
} else {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawenctype" ) + // NOI18N
": " + // NOI18N
rawTypeName_ +
" (" + // NOI18N
Integer.toString( rawSizeInBits_ ) +
" " + // NOI18N
XTCEFunctions.getText( "general_bits" ) + // NOI18N
")" ); // NOI18N
}
break;
case MILSTD_1750A:
if ( ( rawSizeInBits_ == 16 ) ||
( rawSizeInBits_ == 32 ) ||
( rawSizeInBits_ == 48 ) ) {
MilStd1750A floatValue = new MilStd1750A( numericValue,
rawSizeInBits_ );
isFloatRawValueReasonable( floatValue.toIeeeDouble() );
return floatValue.toString();
} else {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawenctype" ) + // NOI18N
": " + // NOI18N
rawTypeName_ +
" (" + // NOI18N
Integer.toString( rawSizeInBits_ ) +
" " + // NOI18N
XTCEFunctions.getText( "general_bits" ) + // NOI18N
")" ); // NOI18N
}
break;
case binary:
return "0x" + numericValue.toString( 16 ); // NOI18N
case UTF8:
return getUncalibratedFromRawString( "UTF-8", numericValue ); // NOI18N
case UTF16:
return getUncalibratedFromRawString( "UTF-16", numericValue ); // NOI18N
default:
// not supported BCD, packedBCD
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawtypenotsupported" ) + // NOI18N
": " + // NOI18N
rawTypeName_ );
}
return ""; // NOI18N
}
/** Retrieve the EU calibrated value of this typed object item when given
* the uncalibrated value.
*
* @param uncalValue String containing the uncalibrated value that is
* derived from the encoded value on the wire or bitfield.
*
* @return String containing the proper EU calibrated representation of the
* uncalibrated value provided by the caller.
*
*/
public String getCalibratedFromUncalibrated( final String uncalValue ) {
clearWarnings();
String calValue = applyCalibrator( uncalValue );
switch ( euTypeName_ ) {
case UNSIGNED:
case SIGNED:
return getCalibratedFromIntegerString( calValue );
case FLOAT32:
case FLOAT64:
case FLOAT128:
return getCalibratedFromFloatString( calValue );
case BOOLEAN:
return getCalibratedFromBooleanNumericString( calValue );
case ENUMERATED:
return getCalibratedValueFromEnumeratedNumericString( calValue );
case STRING:
return calValue;
case BINARY:
// warnings for binary transformations?
// might need 0x protection over entire function
if ( calValue.startsWith( "0x" ) == true ) { // NOI18N
BigInteger intValue =
new BigInteger( calValue.replaceFirst( "0x", "" ), 16 ); // NOI18N
return "0x" + intValue.toString( 16 ); // NOI18N
} else {
BigInteger intValue = new BigInteger( calValue );
return "0x" + intValue.toString( 16 ); // NOI18N
}
case TIME:
try {
if ( timeHandler_ != null ) {
return timeHandler_.getCalibratedFromUncalibrated( uncalValue );
}
} catch ( Exception ex ) {
warn( itemName_ + " " + ex.getLocalizedMessage() ); // NOI18N
}
break;
default:
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_engtypenotsupported" ) + // NOI18N
": " + // NOI18N
euTypeName_ );
break;
}
return ""; // NOI18N
}
/** Retrieve the Raw value of this typed object when given the EU
* calibrated value.
*
* This method is a shortcut to calling both the
* getUncalibratedFromCalibrated() and getRawFromUncalibrated() functions.
* Those functions contain additional details for the reader concerning the
* nature of the data and what is being performed.
*
* The user must interrogate the getWarnings() method to ensure that this
* function did not encounter any problems during conversion. In the
* event that warnings happened, then the return value cannot be used.
*
* @param euValue String containing the EU calibrated value that would
* be encoded on the wire or bitfield.
*
* @return String containing the encoded BitSet suitable for encoding a
* stream with this item value.
*
*/
public BitSet encode( final String euValue ) {
String uncalValue = getUncalibratedFromCalibrated( euValue );
return getRawFromUncalibrated( uncalValue );
}
/** Retrieve the Raw value of this typed object when given the EU
* calibrated value.
*
* This method is a shortcut to calling both the
* getUncalibratedFromCalibrated() and getRawFromUncalibrated() functions.
* Those functions contain additional details for the reader concerning the
* nature of the data and what is being performed.
*
* The user must interrogate the getWarnings() method to ensure that this
* function did not encounter any problems during conversion. In the
* event that warnings happened, then the return value cannot be used.
*
* @param euValue long containing the EU calibrated value that would
* be encoded on the wire or bitfield.
*
* @return String containing the encoded BitSet suitable for encoding a
* stream with this item value.
*
*/
public BitSet encode( final long euValue ) {
String uncalValue = getUncalibratedFromCalibrated( euValue );
return getRawFromUncalibrated( uncalValue );
}
/** Retrieve the Raw value of this typed object when given the EU
* calibrated value.
*
* This method is a shortcut to calling both the
* getUncalibratedFromCalibrated() and getRawFromUncalibrated() functions.
* Those functions contain additional details for the reader concerning the
* nature of the data and what is being performed.
*
* The user must interrogate the getWarnings() method to ensure that this
* function did not encounter any problems during conversion. In the
* event that warnings happened, then the return value cannot be used.
*
* @param euValue double containing the EU calibrated value that would
* be encoded on the wire or bitfield.
*
* @return String containing the encoded BitSet suitable for encoding a
* stream with this item value.
*
*/
public BitSet encode( final double euValue ) {
String uncalValue = getUncalibratedFromCalibrated( euValue );
return getRawFromUncalibrated( uncalValue );
}
/** Retrieve the Raw value of this typed object when given the EU
* calibrated value.
*
* This method is a shortcut to calling both the
* getUncalibratedFromCalibrated() and getRawFromUncalibrated() functions.
* Those functions contain additional details for the reader concerning the
* nature of the data and what is being performed.
*
* The user must interrogate the getWarnings() method to ensure that this
* function did not encounter any problems during conversion. In the
* event that warnings happened, then the return value cannot be used.
*
* @param euValue float containing the EU calibrated value that would
* be encoded on the wire or bitfield.
*
* @return String containing the encoded BitSet suitable for encoding a
* stream with this item value.
*
*/
public BitSet encode( final float euValue ) {
String uncalValue = getUncalibratedFromCalibrated( euValue );
return getRawFromUncalibrated( uncalValue );
}
/** Retrieve the raw binary bits for encoding of this typed object when
* given the uncalibrated value.
*
* @param uncalValue String containing the uncalibrated representation of
* the value.
*
* @return BitSet containing the raw bits.
*
*/
public BitSet getRawFromUncalibrated( final String uncalValue ) {
// TODO Handle Byte order element ByteOrderList in the encoding
BigInteger intValue = BigInteger.ZERO;
try {
if ( euTypeName_ == EngineeringType.TIME ) {
if ( timeHandler_ != null ) {
return timeHandler_.getRawFromUncalibrated( uncalValue );
} else {
return new BitSet( rawSizeInBits_ );
}
} else if ( ( rawTypeName_ == RawType.unsigned ) ||
( rawTypeName_ == RawType.signMagnitude ) ||
( rawTypeName_ == RawType.twosComplement ) ||
( rawTypeName_ == RawType.onesComplement ) ) {
String lowerCalValue = uncalValue.toLowerCase();
if ( lowerCalValue.startsWith( "0x" ) == true ) { // NOI18N
intValue = new BigInteger( lowerCalValue.replaceFirst( "0x", "" ), 16 ); // NOI18N
return getRawFromUncalibrated( intValue );
} else {
intValue = new BigDecimal( lowerCalValue ).toBigIntegerExact();
return getRawFromUncalibrated( intValue );
}
} else if ( rawTypeName_ == RawType.binary ) {
// need to know EU type here!
if ( uncalValue.contains( "-" ) == true ) { // NOI18N
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_binaryinvalid" ) + // NOI18N
" '" + // NOI18N
uncalValue +
"'. " + // NOI18N
XTCEFunctions.getText( "error_encdec_binarynegative" ) ); // NOI18N
} else {
String lowerCalValue = uncalValue.toLowerCase();
intValue = integerStringToBigInteger( lowerCalValue );
}
} else if ( ( rawTypeName_ == RawType.IEEE754_1985 ) ||
( rawTypeName_ == RawType.MILSTD_1750A ) ) {
String reasCalValue = uncalValue.toLowerCase();
if ( reasCalValue.startsWith( "0x" ) == true ) { // NOI18N
BigInteger temp = new BigInteger( reasCalValue.replaceFirst( "0x", "" ), 16 ); // NOI18N
return getRawFromUncalibrated( new BigDecimal( temp ) );
} else {
return getRawFromUncalibrated( new BigDecimal( reasCalValue ) );
}
} else if ( rawTypeName_ == RawType.UTF8 ) {
BigInteger retValue = BigInteger.ZERO;
if ( uncalValue.isEmpty() == false ) {
retValue = new BigInteger( uncalValue.getBytes( StandardCharsets.UTF_8 ) );
}
intValue = encodeUtfString( retValue );
} else if ( rawTypeName_ == RawType.UTF16 ) {
BigInteger retValue = BigInteger.ZERO;
if ( uncalValue.isEmpty() == false ) {
retValue = new BigInteger( uncalValue.getBytes( StandardCharsets.UTF_16 ) );
}
if ( retValue.equals( BigInteger.ZERO ) == true ) {
retValue = new BigInteger( utf16_ );
}
intValue = encodeUtfString( retValue );
} else if ( euTypeName_ == EngineeringType.DURATION ) {
// TODO Add RelativeTime (DURATION) Type
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_engtypenotsupported" ) + // NOI18N
": " + // NOI18N
euTypeName_ );
} else if ( euTypeName_ == EngineeringType.STRUCTURE ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_aggregate" ) ); // NOI18N
} else if ( euTypeName_ == EngineeringType.ARRAY ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_array" ) ); // NOI18N
} else {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_engtypenotsupported" ) + // NOI18N
": " + // NOI18N
euTypeName_ );
}
} catch ( NumberFormatException ex ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText ( "error_encdec_stringinvalid" ) + // NOI18N
" " + // NOI18N
rawTypeName_ +
": '" + // NOI18N
uncalValue +
"'" ); // NOI18N
} catch ( ArithmeticException ex ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText ( "error_encdec_decimalinvalid" ) + // NOI18N
" " + // NOI18N
rawTypeName_ +
": '" + // NOI18N
uncalValue +
"'" ); // NOI18N
}
return makeBitSetFromBigInteger( intValue );
}
/** Retrieve the raw binary bits for encoding of this typed object when
* given the uncalibrated value.
*
* @param uncalValue BigInteger containing the uncalibrated representation
* of the value.
*
* @return BitSet containing the raw bits.
*
*/
public BitSet getRawFromUncalibrated( BigInteger uncalValue ) {
// TODO Handle Byte order element ByteOrderList in the encoding
if ( euTypeName_ == EngineeringType.TIME ) {
if ( timeHandler_ != null ) {
return timeHandler_.getRawFromUncalibrated( uncalValue.toString() );
} else {
return new BitSet( rawSizeInBits_ );
}
}
if ( rawTypeName_ == RawType.unsigned ) {
BigInteger max = new BigInteger( "2" ).pow( rawSizeInBits_ ); // NOI18N
if ( uncalValue.compareTo( max ) == 1 ) {
warn( itemName_ + " overflow value '" + uncalValue +
"', larger than available encoding bits." );
uncalValue = BigInteger.ZERO;
} else if ( isIntegerRawValueReasonable( uncalValue ) == false ) {
uncalValue = BigInteger.ZERO;
}
} else if ( rawTypeName_ == RawType.signMagnitude ) {
BigInteger max = new BigInteger( "2" ).pow( rawSizeInBits_ - 1 ); // NOI18N
BigInteger min = max.negate();
if ( uncalValue.compareTo( max ) == 1 ) {
warn( itemName_ + " overflow value '" + uncalValue +
"', larger than maximum value for encoding." );
uncalValue = BigInteger.ZERO;
} else if ( uncalValue.compareTo (min ) == -1 ) {
warn( itemName_ + " overflow value '" + uncalValue +
"', smaller than minimum value for encoding." );
uncalValue = BigInteger.ZERO;
} else if ( isIntegerRawValueReasonable( uncalValue ) == false ) {
uncalValue = BigInteger.ZERO;
}
if ( uncalValue.compareTo( BigInteger.ZERO ) < 0 ) {
uncalValue = uncalValue.negate();
uncalValue = uncalValue.setBit( rawSizeInBits_ - 1 );
}
} else if ( rawTypeName_ == RawType.twosComplement ) {
BigInteger max = new BigInteger( "2" ).pow( rawSizeInBits_ - 1 ); // NOI18N
BigInteger min = max.negate();
if ( uncalValue.compareTo( max ) == 1 ) {
warn( itemName_ + " overflow value '" + uncalValue +
"', larger than maximum value for encoding." );
uncalValue = BigInteger.ZERO;
} else if ( uncalValue.compareTo (min ) == -1 ) {
warn( itemName_ + " overflow value '" + uncalValue +
"', smaller than minimum value for encoding." );
uncalValue = BigInteger.ZERO;
} else if ( isIntegerRawValueReasonable( uncalValue ) == false ) {
uncalValue = BigInteger.ZERO;
}
} else if ( rawTypeName_ == RawType.onesComplement ) {
BigInteger max = new BigInteger( "2" ).pow( rawSizeInBits_ - 1 ); // NOI18N
BigInteger min = max.negate();
if ( uncalValue.compareTo( max ) == 1 ) {
warn( itemName_ + " overflow value '" + uncalValue +
"', larger than maximum value for encoding." );
uncalValue = BigInteger.ZERO;
} else if ( uncalValue.compareTo (min ) == -1 ) {
warn( itemName_ + " overflow value '" + uncalValue +
"', smaller than minimum value for encoding." );
uncalValue = BigInteger.ZERO;
} else if ( isIntegerRawValueReasonable( uncalValue ) == false ) {
uncalValue = BigInteger.ZERO;
}
if ( uncalValue.compareTo( BigInteger.ZERO ) < 0 ) {
uncalValue = uncalValue.subtract( BigInteger.ONE );
}
} else if ( rawTypeName_ == RawType.binary ) {
// do nothing
} else if ( rawTypeName_ == RawType.IEEE754_1985 ) {
if ( isFloatRawValueReasonable( uncalValue.doubleValue() ) == false ) {
uncalValue = BigInteger.ZERO;
} else {
if ( rawSizeInBits_ == 32 ) {
uncalValue = BigInteger.valueOf( Float.floatToRawIntBits( uncalValue.floatValue() ) );
} else if ( rawSizeInBits_ == 64 ) {
uncalValue = BigInteger.valueOf( Double.doubleToRawLongBits( uncalValue.doubleValue() ) );
} else if ( rawSizeInBits_ == 128 ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawtypenotsupported" ) + // NOI18N
": " + // NOI18N
rawTypeName_ +
" (" + // NOI18N
Integer.toString( rawSizeInBits_ ) +
" " + // NOI18N
XTCEFunctions.getText( "general_bits" ) + // NOI18N
")" ); // NOI18N
} else {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawenctype" ) + // NOI18N
": " + // NOI18N
rawTypeName_ +
" (" + // NOI18N
Integer.toString( rawSizeInBits_ ) +
" " + // NOI18N
XTCEFunctions.getText( "general_bits" ) + // NOI18N
")" ); // NOI18N
}
}
} else if ( rawTypeName_ == RawType.MILSTD_1750A ) {
if ( isFloatRawValueReasonable( uncalValue.doubleValue() ) == false ) {
uncalValue = BigInteger.ZERO;
} else {
if ( ( rawSizeInBits_ == 16 ) ||
( rawSizeInBits_ == 32 ) ||
( rawSizeInBits_ == 48 ) ) {
MilStd1750A milValue = new MilStd1750A( uncalValue.doubleValue(),
rawSizeInBits_ );
uncalValue = BigInteger.valueOf( milValue.toRawBits() );
} else {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawenctype" ) + // NOI18N
": " + // NOI18N
rawTypeName_ +
" (" + // NOI18N
Integer.toString( rawSizeInBits_ ) +
" " + // NOI18N
XTCEFunctions.getText( "general_bits" ) + // NOI18N
")" ); // NOI18N
}
}
} else if ( rawTypeName_ == RawType.UTF8 ) {
String chars = uncalValue.toString();
BigInteger retValue = new BigInteger( chars.getBytes( StandardCharsets.UTF_8 ) );
uncalValue = encodeUtfString( retValue );
} else if ( rawTypeName_ == RawType.UTF16 ) {
String chars = uncalValue.toString();
BigInteger retValue = new BigInteger( chars.getBytes( StandardCharsets.UTF_16 ) );
if ( retValue.equals( BigInteger.ZERO ) == true ) {
retValue = new BigInteger( utf16_ );
}
uncalValue = encodeUtfString( retValue );
} else if ( euTypeName_ == EngineeringType.TIME ) {
// TODO Add AbsoluteTime (TIME) Type
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_engtypenotsupported" ) + // NOI18N
": " + // NOI18N
euTypeName_ );
uncalValue = BigInteger.ZERO;
} else if ( euTypeName_ == EngineeringType.DURATION ) {
// TODO Add RelativeTime (DURATION) Type
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_engtypenotsupported" ) + // NOI18N
": " + // NOI18N
euTypeName_ );
uncalValue = BigInteger.ZERO;
} else if ( euTypeName_ == EngineeringType.STRUCTURE ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_aggregate" ) ); // NOI18N
uncalValue = BigInteger.ZERO;
} else if ( euTypeName_ == EngineeringType.ARRAY ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_array" ) ); // NOI18N
uncalValue = BigInteger.ZERO;
} else {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_engtypenotsupported" ) + // NOI18N
": " + // NOI18N
euTypeName_ );
uncalValue = BigInteger.ZERO;
}
return makeBitSetFromBigInteger( uncalValue );
}
/** Retrieve the raw binary bits for encoding of this typed object when
* given the uncalibrated value.
*
* @param uncalValue long containing the uncalibrated representation of
* the value.
*
* @return BitSet containing the raw bits.
*
*/
public BitSet getRawFromUncalibrated( final long uncalValue ) {
BigInteger intValue = BigInteger.valueOf( uncalValue );
return getRawFromUncalibrated( intValue );
}
/** Retrieve the raw binary bits for encoding of this typed object when
* given the uncalibrated value.
*
* @param uncalValue BigDecimal containing the uncalibrated representation
* of the value.
*
* @return BitSet containing the raw bits.
*
*/
public BitSet getRawFromUncalibrated( final BigDecimal uncalValue ) {
// TODO Handle Byte order element ByteOrderList in the encoding
BigInteger intValue = BigInteger.ZERO;
if ( ( rawTypeName_ == RawType.unsigned ) ||
( rawTypeName_ == RawType.signMagnitude ) ||
( rawTypeName_ == RawType.twosComplement ) ||
( rawTypeName_ == RawType.onesComplement ) ) {
try {
return getRawFromUncalibrated( uncalValue.toBigIntegerExact() );
} catch ( NumberFormatException ex ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText ( "error_encdec_decimalinvalid" ) + // NOI18N
" " + // NOI18N
rawTypeName_ +
": '" + // NOI18N
uncalValue +
"'" ); // NOI18N
}
} else if ( rawTypeName_ == RawType.binary ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawtypenotsupported" ) + // NOI18N
": " + // NOI18N
rawTypeName_ +
" (" + // NOI18N
Integer.toString( rawSizeInBits_ ) +
" " + // NOI18N
XTCEFunctions.getText( "general_bits" ) + // NOI18N
")" ); // NOI18N
} else if ( rawTypeName_ == RawType.IEEE754_1985 ) {
if ( isFloatRawValueReasonable( uncalValue.doubleValue() ) == false ) {
intValue = BigInteger.ZERO;
} else {
if ( rawSizeInBits_ == 32 ) {
intValue = BigInteger.valueOf( Float.floatToRawIntBits( uncalValue.floatValue() ) );
} else if ( rawSizeInBits_ == 64 ) {
intValue = BigInteger.valueOf( Double.doubleToRawLongBits( uncalValue.doubleValue() ) );
} else if ( rawSizeInBits_ == 128 ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawtypenotsupported" ) + // NOI18N
": " + // NOI18N
rawTypeName_ +
" (" + // NOI18N
Integer.toString( rawSizeInBits_ ) +
" " + // NOI18N
XTCEFunctions.getText( "general_bits" ) + // NOI18N
")" ); // NOI18N
} else {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawenctype" ) + // NOI18N
": " + // NOI18N
rawTypeName_ +
" (" + // NOI18N
Integer.toString( rawSizeInBits_ ) +
" " + // NOI18N
XTCEFunctions.getText( "general_bits" ) + // NOI18N
")" ); // NOI18N
}
}
} else if ( rawTypeName_ == RawType.MILSTD_1750A ) {
if ( isFloatRawValueReasonable( uncalValue.doubleValue() ) == false ) {
intValue = BigInteger.ZERO;
} else {
if ( ( rawSizeInBits_ == 16 ) ||
( rawSizeInBits_ == 32 ) ||
( rawSizeInBits_ == 48 ) ) {
MilStd1750A milValue = new MilStd1750A( uncalValue.doubleValue(),
rawSizeInBits_ );
intValue = BigInteger.valueOf( milValue.toRawBits() );
} else {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawenctype" ) + // NOI18N
": " + // NOI18N
rawTypeName_ +
" (" + // NOI18N
Integer.toString( rawSizeInBits_ ) +
" " + // NOI18N
XTCEFunctions.getText( "general_bits" ) + // NOI18N
")" ); // NOI18N
}
}
} else if ( rawTypeName_ == RawType.UTF8 ) {
String chars = uncalValue.toString();
BigInteger retValue = new BigInteger( chars.getBytes( StandardCharsets.UTF_8 ) );
intValue = encodeUtfString( retValue );
} else if ( rawTypeName_ == RawType.UTF16 ) {
String chars = uncalValue.toString();
BigInteger retValue = new BigInteger( chars.getBytes( StandardCharsets.UTF_16 ) );
if ( retValue.equals( BigInteger.ZERO ) == true ) {
retValue = new BigInteger( utf16_ );
}
intValue = encodeUtfString( retValue );
} else if ( euTypeName_ == EngineeringType.TIME ) {
// TODO Add AbsoluteTime (TIME) Type
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_engtypenotsupported" ) + // NOI18N
": " + // NOI18N
euTypeName_ );
} else if ( euTypeName_ == EngineeringType.DURATION ) {
// TODO Add RelativeTime (DURATION) Type
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_engtypenotsupported" ) + // NOI18N
": " + // NOI18N
euTypeName_ );
} else if ( euTypeName_ == EngineeringType.STRUCTURE ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_aggregate" ) ); // NOI18N
} else if ( euTypeName_ == EngineeringType.ARRAY ) {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_array" ) ); // NOI18N
} else {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_engtypenotsupported" ) + // NOI18N
": " + // NOI18N
euTypeName_ );
}
return makeBitSetFromBigInteger( intValue );
}
/** Retrieve the raw binary bits for encoding of this typed object when
* given the uncalibrated value.
*
* @param uncalValue double containing the uncalibrated representation of
* the value.
*
* @return BitSet containing the raw bits.
*
*/
public BitSet getRawFromUncalibrated( final double uncalValue ) {
BigDecimal decimalValue = new BigDecimal( uncalValue );
return getRawFromUncalibrated( decimalValue );
}
/** Retrieve the raw binary bits for encoding of this typed object when
* given the uncalibrated value.
*
* @param uncalValue float containing the uncalibrated representation of
* the value.
*
* @return BitSet containing the raw bits.
*
*/
public BitSet getRawFromUncalibrated( final float uncalValue ) {
BigDecimal decimalValue = new BigDecimal( uncalValue );
return getRawFromUncalibrated( decimalValue );
}
/** Retrieve the uncalibrated value of an EU calibrated value for this
* typed object.
*
* @param euValue String containing a value of this item represented in
* EU/calibrated form.
*
* @return String containing the uncalibrated value.
*
*/
public String getUncalibratedFromCalibrated( final String euValue ) {
switch ( euTypeName_ ) {
case BOOLEAN: {
BigInteger integerValue = integerFromBooleanType( euValue );
isIntegerRawValueReasonable( integerValue );
return uncalibrateIntegerType( integerValue );
}
case ENUMERATED: {
BigInteger integerValue = integerFromEnumerationType( euValue );
return uncalibrateIntegerType( integerValue );
}
case STRING:
return euValue;
case BINARY:
return "0x" + // NOI18N
integerStringToBigInteger( euValue ).toString( 16 );
case FLOAT32:
case FLOAT64:
case FLOAT128:
try {
if ( euValue.startsWith( "0x" ) == true ) { // NOI18N
BigInteger intValue = new BigInteger( euValue.replaceFirst( "0x", "" ), 16 ); // NOI18N
BigDecimal calValue = new BigDecimal( intValue );
//isFloatRawValueReasonable( calValue.doubleValue() );
return uncalibrateFloatType( calValue );
} else if ( euValue.startsWith( "0X" ) == true ) { // NOI18N
BigInteger intValue = new BigInteger( euValue.replaceFirst( "0X", "" ), 16 ); // NOI18N
BigDecimal calValue = new BigDecimal( intValue );
//isFloatRawValueReasonable( calValue.doubleValue() );
return uncalibrateFloatType( calValue );
}
BigDecimal calValue = new BigDecimal( euValue );
//isFloatRawValueReasonable( calValue.doubleValue() );
return uncalibrateFloatType( calValue );
} catch ( NumberFormatException ex ) {
warn( itemName_ +
" Invalid String value for uncalibrate " +
rawTypeName_ +
" of '" +
euValue +
"'" );
}
break;
case UNSIGNED:
case SIGNED:
try {
if ( euValue.startsWith( "0x" ) == true ) { // NOI18N
return uncalibrateIntegerType( new BigInteger( euValue.replaceFirst( "0x", "" ), 16 ) ); // NOI18N
} else if ( euValue.startsWith( "0X" ) == true ) { // NOI18N
return uncalibrateIntegerType( new BigInteger( euValue.replaceFirst( "0X", "" ), 16 ) ); // NOI18N
}
BigDecimal testValue = new BigDecimal( euValue );
if ( ( testValue.doubleValue() % 1 ) != 0 ) {
warn( itemName_ +
" Invalid Integer value for uncalibrate of '" +
euValue + "'" );
} else {
BigInteger intValue = testValue.toBigInteger();
return uncalibrateIntegerType( intValue );
}
} catch ( NumberFormatException ex ) {
warn( itemName_ +
" Invalid Integer value for uncalibrate of '" +
euValue +
"'" );
}
break;
case TIME:
try {
if ( timeHandler_ != null ) {
return timeHandler_.getUncalibratedFromCalibrated( euValue );
}
} catch ( Exception ex ) {
warn( itemName_ + " " + ex.getLocalizedMessage() ); // NOI18N
}
break;
case DURATION:
// TODO Add RelativeTime (DURATION) Type
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_engtypenotsupported" ) + // NOI18N
": " + // NOI18N
euTypeName_ );
break;
case STRUCTURE:
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_aggregate" ) ); // NOI18N
break;
case ARRAY:
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_array" ) ); // NOI18N
break;
default:
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_engtypenotsupported" ) + // NOI18N
": " + // NOI18N
euTypeName_ );
break;
}
return "";
}
/** Retrieve the uncalibrated value of an EU calibrated value for this
* typed object.
*
* @param euValue BigInteger containing a value of this item represented in
* EU/calibrated form.
*
* @return String containing the uncalibrated value.
*
*/
public String getUncalibratedFromCalibrated( final BigInteger euValue ) {
return getUncalibratedFromCalibrated( euValue.toString() );
}
/** Retrieve the uncalibrated value of an EU calibrated value for this
* typed object.
*
* @param euValue long containing a value of this item represented in
* EU/calibrated form.
*
* @return String containing the uncalibrated value.
*
*/
public String getUncalibratedFromCalibrated( final long euValue ) {
BigInteger intValue = BigInteger.valueOf( euValue );
return getUncalibratedFromCalibrated( intValue );
}
/** Retrieve the uncalibrated value of an EU calibrated value for this
* typed object.
*
* @param euValue BigDecimal containing a value of this item represented in
* EU/calibrated form.
*
* @return String containing the uncalibrated value.
*
*/
public String getUncalibratedFromCalibrated( final BigDecimal euValue ) {
return getUncalibratedFromCalibrated( euValue.doubleValue() );
}
/** Retrieve the uncalibrated value of an EU calibrated value for this
* typed object.
*
* @param euValue double containing a value of this item represented in
* EU/calibrated form.
*
* @return String containing the uncalibrated value.
*
*/
public String getUncalibratedFromCalibrated( final double euValue ) {
return getUncalibratedFromCalibrated( Double.toString( euValue ) );
}
/** Retrieve the uncalibrated value of an EU calibrated value for this
* typed object.
*
* @param euValue float containing a value of this item represented in
* EU/calibrated form.
*
* @return String containing the uncalibrated value.
*
*/
public String getUncalibratedFromCalibrated( final float euValue ) {
return getUncalibratedFromCalibrated( Float.toString( euValue ) );
}
/** Function to resolve a Boolean Engineering Type, which has a flexible
* set of EU values, into the numeric calibrated value.
*
* This function could have been implemented by creating a bogus set of
* enumerations, where just 0 and 1 are implememnted, using the attributes
* of @zeroStringValue and @oneStringValue, but it was just as simple to
* create this and it seemed like less overhead. A warning message is
* added to the warnings list in the event that the engineering value does
* not match and the return value will be BigInteger.ZERO.
*
* @param euValue String containing the user provided engineering value for
* this Boolean type Parameter/Argument.
*
* @return BigInteger containing either ZERO or ONE, which are constants
* for the BigInteger class.
*
*/
private BigInteger integerFromBooleanType( final String euValue ) {
if ( euValue.equals( booleanZeroString_ ) == true ) {
return BigInteger.ZERO;
} else if ( euValue.equals( booleanOneString_ ) == true ) {
return BigInteger.ONE;
} else {
warn( itemName_ +
" Invalid EU Boolean value of '" + euValue + "'" );
}
return BigInteger.ZERO;
}
/** Function to resolve an Enumerated Engineering Type into the numeric
* calibrated value.
*
* This function searches the labels of the EnumerationList in the XTCE
* data model to find a match. It takes into account that some
* enumerations have ranges, and if there is an overlap, it will end up
* returning the first match. Since this function supports the encode()
* method, enumeration labels that have ranges cannot be exactly
* determined, so the raw value returned will always be the first valid
* value for the label, if it is in a range. A warning will be posted to
* the warnings list, but it should be considered harmless in this case.
*
* @param euValue String containing the enumeration label provided by the
* user that wishes to encode() this Parameter/Argument into a raw value.
*
* @return BigInteger containing the raw value associated with the provided
* enumeration label, or BigInteger.ZERO if the label was not located. A
* warning will be posted to the warnings list if this occurs.
*
*/
private BigInteger integerFromEnumerationType( final String euValue ) {
for ( ValueEnumerationType enumItem : enums_ ) {
if ( enumItem.getLabel().equals( euValue ) == false ) {
continue;
}
if ( enumItem.getMaxValue() != null ) {
warn( "Enumeration label '" +
enumItem.getLabel() +
"' for " +
itemName_ +
" has values '" +
enumItem.getValue().toString() +
"' through '" +
enumItem.getMaxValue().toString() +
"', using lowest possible value" );
}
return enumItem.getValue();
}
warn( itemName_ +
" Invalid EU Enumeration value of '" + euValue + "'" );
return BigInteger.ZERO;
}
private String uncalibrateIntegerType( final BigInteger calValue ) {
switch ( rawTypeName_ ) {
case unsigned:
case signMagnitude:
case twosComplement:
case onesComplement: {
BigDecimal decValue = floatEncodingUncalibrate( calValue );
BigInteger uncalValue = decValue.toBigInteger();
if ( isIntegerRawValueReasonable( uncalValue ) == false ) {
return "0"; // NOI18N
}
return uncalValue.toString();
}
case binary:
return calValue.toString();
case IEEE754_1985:
case MILSTD_1750A: {
BigDecimal uncalValue =
floatEncodingUncalibrate( new BigDecimal( calValue ) );
if ( isFloatRawValueReasonable( uncalValue.doubleValue() ) == false ) {
return "0.0"; // NOI18N
}
return Double.toString( uncalValue.doubleValue() );
}
case UTF8:
case UTF16:
return calValue.toString();
default:
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawtypenotsupported" ) + // NOI18N
": " + // NOI18N
rawTypeName_ );
}
return "0"; // NOI18N
}
private String uncalibrateFloatType( final BigDecimal calValue ) {
switch ( rawTypeName_ ) {
case unsigned:
case signMagnitude:
case twosComplement:
case onesComplement: {
BigDecimal decValue = floatEncodingUncalibrate( calValue );
BigInteger uncalValue = decValue.toBigInteger();
if ( isIntegerRawValueReasonable( uncalValue ) == false ) {
return "0"; // NOI18N
}
return uncalValue.toString();
}
case binary:
return calValue.toString();
case IEEE754_1985:
case MILSTD_1750A: {
BigDecimal uncalValue =
floatEncodingUncalibrate( calValue );
if ( isFloatRawValueReasonable( uncalValue.doubleValue() ) == false ) {
return "0.0"; // NOI18N
}
return Double.toString( uncalValue.doubleValue() );
}
case UTF8:
case UTF16:
return calValue.toString();
default:
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_rawtypenotsupported" ) + // NOI18N
": " + // NOI18N
rawTypeName_ );
}
return "0";
}
private String getUncalibratedFromRawString( final String encoding,
final BigInteger uncalValue ) {
// we need to accomodate the TerminationChar and the LeadingSize here
String retValue = new String( uncalValue.toByteArray(),
Charset.forName( encoding ) );
if ( retValue.length() == 0 ) {
return ""; // NOI18N
}
int endIndex = retValue.length() - 1;
while ( retValue.charAt( endIndex ) == '\0' ) { // NOI18N
if ( endIndex == 0 ) {
return ""; // NOI18N
} else {
retValue = retValue.substring( 0, endIndex );
}
endIndex = retValue.length() - 1;
}
return retValue;
}
private String getCalibratedFromIntegerString( final String calValue ) {
try {
// the idea here is to allow for a tolerance when doing the
// conversion of string to integer taking into account that float
// calculations can have noise. if the decimal is substantive,
// then an exception is thrown from toBigIntegerExact().
BigInteger largerValue =
new BigDecimal( calValue ).movePointRight( 6 ).toBigInteger();
BigDecimal smallerValue =
new BigDecimal( largerValue.divide( new BigInteger( "1000000" ) ) ); // NOI18N
BigInteger retValue = smallerValue.toBigIntegerExact();
if ( validRange_.isValidRangeApplied() == true ) {
checkValidRangeCalibrated( new BigDecimal( retValue ), calValue );
}
return retValue.toString();
} catch ( Exception ex ) {
warn( itemName_ + " Calibrated value '" +
calValue + "' is not representative of an integer" );
}
return "";
}
private String getCalibratedFromFloatString( final String calValue ) {
try {
BigDecimal retValue = new BigDecimal( calValue );
if ( validRange_.isValidRangeApplied() == true ) {
checkValidRangeCalibrated( retValue, calValue );
}
return retValue.toString();
} catch ( NumberFormatException ex ) {
warn( itemName_ + " Calibrated value '" +
calValue + "' is not representative of a floating " +
"point number" );
}
return "";
}
private String getCalibratedFromBooleanNumericString( final String uncalValue ) {
try {
BigInteger intValue = new BigInteger( uncalValue );
if ( intValue.compareTo( BigInteger.ZERO ) == 0 ) {
return booleanZeroString_;
} else if ( intValue.compareTo( BigInteger.ONE ) == 0 ) {
return booleanOneString_;
}
warn( itemName_ + " Boolean undefined for " +
" uncalibrated value '" + uncalValue + "'" );
} catch ( NumberFormatException ex ) {
warn( itemName_ + " uncalibrated value '" +
uncalValue + "' is not an integer number needed for an " +
"boolean type label" );
}
return "";
}
private String getCalibratedValueFromEnumeratedNumericString( final String uncalValue ) {
try {
BigInteger intValue = new BigInteger( uncalValue );
for ( ValueEnumerationType entry : enums_ ) {
if ( entry.getValue().compareTo( intValue ) == 0 ) {
return entry.getLabel();
} else if ( entry.getMaxValue() != null ) {
if ( ( entry.getValue().compareTo( intValue ) <= 0 ) &&
( entry.getMaxValue().compareTo( intValue ) >= 0 ) ) {
return entry.getLabel();
}
}
}
warn( itemName_ + " Enumeration undefined for " +
"uncalibrated value '" + uncalValue + "'" );
} catch ( NumberFormatException ex ) {
warn( itemName_ + " uncalibrated value '" +
uncalValue + "' is not an integer number needed for an " +
"enumerated type label" );
}
return "";
}
private void checkValidRangeCalibrated( BigDecimal retValue,
String calValue ) {
try {
if ( validRange_.isHighValueCalibrated() == true ) {
BigDecimal high = new BigDecimal( validRange_.getHighValue() );
if ( validRange_.isHighValueInclusive() == true ) {
if ( high.compareTo( retValue ) == -1 ) {
warn( itemName_ + " Calibrated value '" +
calValue + "' is too large for valid " +
"inclusive max value of '" +
validRange_.getHighValue() + "'" );
}
} else {
if ( high.compareTo( retValue ) < 1 ) {
warn( itemName_ + " Calibrated value '" +
calValue + "' is too large for valid " +
"exclusive max value of '" +
validRange_.getHighValue() + "'" );
}
}
}
if ( validRange_.isLowValueCalibrated() == true ) {
BigDecimal low = new BigDecimal( validRange_.getLowValue() );
if ( validRange_.isLowValueInclusive() == true ) {
if ( low.compareTo( retValue ) == 1 ) {
warn( itemName_ + " Calibrated value '" +
calValue + "' is too small for valid " +
"inclusive min value of '" +
validRange_.getLowValue() + "'" );
}
} else {
if ( low.compareTo( retValue ) > -1 ) {
warn( itemName_ + " Calibrated value '" +
calValue + "' is too small for valid " +
"exclusive min value of '" +
validRange_.getLowValue() + "'" );
}
}
}
} catch ( NumberFormatException ex ) {
warn( itemName_ + " Valid Range contains value that " +
"is not representative of the numeric engineering type " +
euTypeName_ );
}
}
/** Private method to calculate and apply the calibrator to the
* uncalibrated value.
*
* This method does not support MathOperationCalibrator elements and will
* record a warning. MathOperationCalibrators are quietly ignored.
*
* @param uncalValue String containing the uncalibrated value derived from
* the raw binary value in the stream.
*
* @return String containing the value as calibrated, or a quick return of
* the original value if no calibrator exists to act on.
*
*/
private String applyCalibrator( final String uncalValue ) {
if ( defCal_ == null ) {
return uncalValue;
}
try {
Calibration calObj;
if ( defCal_.getPolynomialCalibrator() != null ) {
calObj = new PolynomialCalibration( defCal_.getPolynomialCalibrator(), validRange_, rawSizeInBits_, rawTypeName_ );
} else if ( defCal_.getSplineCalibrator() != null ) {
calObj = new SplineCalibration( defCal_.getSplineCalibrator() );
} else if ( defCal_.getMathOperationCalibrator() != null ) {
calObj = new MathOperationCalibration( defCal_.getMathOperationCalibrator() );
} else {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_unknown_calibrator" ) ); // NOI18N
return uncalValue;
}
return calObj.calibrate( Double.valueOf( uncalValue ) ).toString();
} catch ( XTCEDatabaseException ex ) {
warn( itemName_ + " " + ex.getLocalizedMessage() ); // NOI18N
}
return uncalValue;
}
private BigInteger encodeUtfString( BigInteger retValue ) {
long bitLength = retValue.toByteArray().length * 8;
if ( bitLength > rawSizeInBits_ ) {
warn( "String length for encoding " +
rawTypeName_ +
" item " +
itemName_ +
" is " +
Long.toString( bitLength ) +
" which exceeds fixed length size of " +
Long.toString( rawSizeInBits_) );
}
if ( retValue.equals( BigInteger.ZERO ) == true ) {
return retValue;
}
while ( bitLength < rawSizeInBits_ ) {
retValue = retValue.shiftLeft( 8 );
bitLength = retValue.toByteArray().length * 8;
//retValue = retValue.add( ); for termination char
}
return retValue;
}
/** Function to create the raw binary bits for populating a container
* binary based on the encoded value of this named and typed item from the
* XTCE data model.
*
* The caller provides the raw value in the form of a BigInteger
* and this function walks through the bits of that value, ensuring to
* use all the bits that are in the raw encoded size. It sets the BitSet
* such that bit 0 of the BitSet is the least significant bit and the
* highest (rawSizeInBits_) is the most significant bit. If the order is
* reversed by the encoding attribute @bitOrder, then the reverse happens.
*
* @param rawValue BigInteger containing the value to encode into a raw
* BitSet for inclusion into a container object, either Telemetry or
* Telecommand.
*
* @return BitSet suitable for inclusion into a Telemetry or Telecommand
* container by simply walking the length and placing the bits into the
* container. All ordering has already been handled.
*
*/
public BitSet encodeRawBits( BigInteger rawValue ) {
// TODO Handle Byte order element ByteOrderList in the encoding
BitSet rawBits = new BitSet( rawSizeInBits_ );
// this code is not a part of the encoding logic, rather it compensates
// for the design of Java BigInteger, which internallys stores as a
// twosComplement. When creating from hex input, this would not need
// to be invoked. A string version of this function would not need to
// do this, either. It could operate on a byte[].
if ( rawValue.compareTo( BigInteger.ZERO ) < 0 ) {
if ( rawTypeName_ == RawType.signMagnitude ) {
rawValue = rawValue.negate().setBit( rawSizeInBits_ - 1 );
} else if ( rawTypeName_ == RawType.onesComplement ) {
rawValue = rawValue.subtract( BigInteger.ONE );
}
}
if ( rawBitOrder_.equals( "mostSignificantBitFirst" ) == true ) { // NOI18N
for ( int iii = rawSizeInBits_ - 1; iii >= 0; --iii ) {
rawBits.set( iii, rawValue.testBit( iii ) );
}
} else {
for ( int iii = rawSizeInBits_ - 1; iii >= 0; --iii ) {
rawBits.set( rawSizeInBits_ - iii - 1, rawValue.testBit( iii ) );
}
}
return rawBits;
}
/** Sets the Valid Range attributes of this object based on a general
* type specification from the XTCE data model, which all inherit from the
* NameDescriptionType.
*
* @param typeObj NameDescriptionType containing the type information for
* this named and typed Parameter/Argument.
*
*/
private void setValidRangeAttributes( final XTCETypedObject item ) {
validRange_ = item.getValidRange();
// these private members are probably not necessary. might remove
NameDescriptionType typeObj = item.getTypeReference();
if ( typeObj instanceof BooleanDataType ) {
booleanZeroString_ = ((BooleanDataType)typeObj).getZeroStringValue();
booleanOneString_ = ((BooleanDataType)typeObj).getOneStringValue();
}
}
private BitSet makeBitSetFromBigInteger( final BigInteger rawValue ) {
BitSet rawBits = new BitSet( rawSizeInBits_ );
if ( rawBitOrder_.equals( "mostSignificantBitFirst" ) == true ) { // NOI18N
for ( int iii = rawSizeInBits_ - 1; iii >= 0; --iii ) {
rawBits.set( iii, rawValue.testBit( iii ) );
}
} else {
for ( int iii = rawSizeInBits_ - 1; iii >= 0; --iii ) {
rawBits.set( rawSizeInBits_ - iii - 1, rawValue.testBit( iii ) );
}
}
return rawBits;
}
/** Convert the BitSet object from the encode() method over to a hex byte
* string, ordered from the most significant byte to the least significant
* byte.
*
* The most significant bits are padded with zero in this case when the
* raw size is not on an even 8 bit boundary. This results in the function
* never returning a hex string that is less than 2 characters for each
* byte, with a minimum of 1 byte. A "0x" is prepended. If the exact
* raw size is needed, call the rawSizeInBits() method to determine which
* of the uppermost bits are extraneous.
*
* @param bits BitSet returned from the encode() function.
*
* @return String containing the hex of the raw value to be encoded,
* subject to the explanation above associated with this function.
*
*/
public final String bitSetToHex( final BitSet bits ) {
int bitCount = rawSizeInBits_;
if ( ( rawSizeInBits_ % 8 ) != 0 ) {
bitCount += 8 - ( rawSizeInBits_ % 8 );
}
int byteCount = bitCount / 8;
StringBuilder sb = new StringBuilder( "0x" ); // NOI18N
byte[] bytes = bits.toByteArray();
for ( int iii = byteCount - 1; iii >= 0; --iii ) {
if ( iii < bytes.length ) {
sb.append( String.format( "%02x", bytes[iii] ) ); // NOI18N
} else {
sb.append( "00" ); // NOI18N
}
}
return sb.toString();
}
/** Convert the BitSet object from the encode() method over to a integral
* number, ordered from the most significant byte to the least significant
* byte.
*
* @param bits BitSet returned from the encode() function.
*
* @return String containing the hex of the raw value to be encoded,
* subject to the explanation above associated with this function.
*
*/
public final BigInteger bitSetToNumber( final BitSet bits ) {
int bitCount = rawSizeInBits_;
if ( ( rawSizeInBits_ % 8 ) != 0 ) {
bitCount += 8 - ( rawSizeInBits_ % 8 );
}
int byteCount = bitCount / 8;
StringBuilder sb = new StringBuilder();
byte[] bytes = bits.toByteArray();
for ( int iii = byteCount - 1; iii >= 0; --iii ) {
if ( iii < bytes.length ) {
sb.append( String.format( "%02x", bytes[iii] ) ); // NOI18N
} else {
sb.append( "00" ); // NOI18N
}
}
if ( bits.length() > rawSizeInBits_ ) {
warn( itemName_ + " raw binary length '" +
Integer.toString( bits.length() ) + "' overflows raw " +
"encoding length of '" + Integer.toString( rawSizeInBits_ ) +
"'" );
}
return new BigInteger( sb.toString(), 16 );
}
/** Convert the BitSet object from the encode() method over to a binary
* string of zeros and ones, ordered from most significant bit to least
* significant bit.
*
* @param bits BitSet containing the bits returned from the encode()
* function.
*
* @return String containing the binary zeros and ones, with all bit
* positions populated for the entire length of the raw size. The number
* of bits will always exactly equal the raw encoding size, with the upper
* possible unused bits padded with zeros.
*
*/
public final String bitSetToBinary( final BitSet bits ) {
StringBuilder sb = new StringBuilder();
for ( int iii = rawSizeInBits_ - 1; iii >= 0; --iii ) {
sb.append( bits.get( iii ) == true ? "1" : "0" ); // NOI18N
}
return sb.toString();
}
/** Convert a string representation of a Raw Value to a BigInteger.
*
* All raw values are represented in the form of hexadecimal or perhaps in
* more rare occasions, a user may present a base 10 number. The
* BigInteger is a convenient container for an arbitrary length series of
* bytes that is easy to work with in hex form.
*
* A warning is logged if the string representation cannot be converted to
* numeric.
*
* @param rawValue String containing the candidate raw representation.
*
* @return BigInteger containing the raw value or zero if a warning was
* logged.
*
*/
public BigInteger integerStringToBigInteger( final String rawValue ) {
BigInteger rawInteger = BigInteger.ZERO;
try {
String reasValue = rawValue.toLowerCase();
if ( reasValue.startsWith( "0x" ) == true ) { // NOI18N
rawInteger =
new BigInteger( reasValue.replaceFirst( "0x", "" ), 16 ); // NOI18N
} else {
rawInteger = new BigInteger( reasValue );
}
} catch ( NumberFormatException ex ) {
warn( itemName_ + " raw value provided '" + rawValue +
"' is not a properly formatted hex or integer." );
}
return rawInteger;
}
private BigDecimal floatEncodingUncalibrate( final Number calValue ) {
try {
Calibration calObj;
if ( defCal_ == null ) {
return new BigDecimal( calValue.toString() );
} else if ( defCal_.getPolynomialCalibrator() != null ) {
calObj = new PolynomialCalibration( defCal_.getPolynomialCalibrator(), validRange_, rawSizeInBits_, rawTypeName_ );
} else if ( defCal_.getSplineCalibrator() != null ) {
calObj = new SplineCalibration( defCal_.getSplineCalibrator() );
} else if ( defCal_.getMathOperationCalibrator() != null ) {
calObj = new MathOperationCalibration( defCal_.getMathOperationCalibrator() );
} else {
warn( itemName_ +
" " + // NOI18N
XTCEFunctions.getText( "error_encdec_unknown_calibrator" ) ); // NOI18N
return new BigDecimal( calValue.toString() );
}
return new BigDecimal( calObj.uncalibrate( calValue ).doubleValue() );
} catch ( XTCEDatabaseException ex ) {
warn( itemName_ + " " + ex.getLocalizedMessage() ); // NOI18N
}
return new BigDecimal( calValue.toString() );
}
/** Sets the internal enumeration list information in the event that this
* is an Enumerated Type Parameter/Argument.
*
* @param typeObj XTCETypedObject base class for the Type information
* about this Parameter/Argument.
*
*/
private void setEnumerationList( final XTCETypedObject item ) {
enums_ = item.getEnumerations();
}
/** Sets the internal default calibrator list information in the event that
* this Parameter/Argument has an encoding type that supports calibration.
*
* The types that support Calibrators are Integer and Float data encoding.
*
*/
private void setDefaultCalibrator( final XTCETypedObject item ) {
defCal_ = item.getDefaultCalibrator();
}
/** Check for reasonableness of the raw value to encode to an integer type
* encoding.
*
* This method first figures out the range of possible values based on the
* size in bits and the signed state. It then checks if the value should
* be restricted further by a possibly present ValidRange element. It
* applies those limits if they are intended for the raw value.
*
* @param rawValue BigInteger containing the raw value that will be encoded
* if it turns out to be reasonable.
*
* @return boolean indicating if this function thinks the value is
* reasonable to fit in the allowable size and range.
*
*/
public boolean isIntegerRawValueReasonable( final BigInteger rawValue ) {
// first find the general size applicable to the bit length
boolean minInclusive = true;
boolean maxInclusive = true;
long minValue = 0;
long maxValue = (long)Math.pow( 2, rawSizeInBits_ ) - 1;
// if it is signed, then correct that range
if ( ( rawTypeName_ == RawType.signMagnitude ) ||
( rawTypeName_ == RawType.onesComplement ) ||
( rawTypeName_ == RawType.twosComplement ) ) {
minValue = -1 * (long)Math.pow( 2, ( rawSizeInBits_ - 1 ) );
maxValue = (long)Math.pow( 2, ( rawSizeInBits_ - 1 ) ) - 1;
}
// if a ValidRange element exists then we want to filter the min and
// max through that, but only if it applies to RAW
if ( validRange_.isValidRangeApplied() == true ) {
if ( validRange_.isLowValueCalibrated() == false ) {
minValue = Math.round( Double.parseDouble( validRange_.getLowValue() ) );
if ( validRange_.isLowValueInclusive() == false ) {
minInclusive = false;
}
}
if ( validRange_.isHighValueCalibrated() == false ) {
maxValue = Math.round( Double.parseDouble( validRange_.getHighValue() ) );
if ( validRange_.isHighValueInclusive() == false ) {
maxInclusive = false;
}
}
}
// check the special negative case first
if ( rawTypeName_ == RawType.unsigned ) {
if ( rawValue.signum() < 0 ) {
warn( itemName_ + " Unsigned value is '" +
rawValue.toString() +
"', which cannot be negative for unsigned encoding" );
return false;
}
}
// TODO: BigIntegers screw this up on long overflow!
// check for the boundary conditions with the minimum first
if ( minInclusive == false ) {
if ( minValue >= rawValue.longValue() ) {
warn( itemName_ + " Encoded value '" +
rawValue.toString() +
"' is too small for valid " +
"exclusive min value of '" +
Long.toString( minValue ) + "' on encoding of " +
rawTypeName_ );
return false;
}
} else {
if ( minValue > rawValue.longValue() ) {
warn( itemName_ + " Encoded value '" +
rawValue.toString() +
"' is too small for valid " +
"inclusive min value of '" +
Long.toString( minValue ) + "' on encoding of " +
rawTypeName_ );
return false;
}
}
// check for the boundary conditions with the maximum
if ( maxInclusive == false ) {
if ( maxValue <= rawValue.longValue() ) {
warn( itemName_ + " Encoded value '" +
rawValue.toString() +
"' is too large for valid " +
"exclusive max value of '" +
Long.toString( maxValue ) + "' on encoding of " +
rawTypeName_ );
return false;
}
} else {
if ( maxValue < rawValue.longValue() ) {
warn( itemName_ + " Encoded value '" +
rawValue.toString() +
"' is too large for valid " +
"inclusive max value of '" +
Long.toString( maxValue ) + "' on encoding of " +
rawTypeName_ );
return false;
}
}
return true;
}
/** Check for reasonableness of the raw value to encode to a float type
* encoding.
*
* This method first figures out the range of possible values based on the
* size in bits of the floating point range. This is generally not very
* useful because the range is very wide. It then checks if the value
* should be restricted further by a possibly present ValidRange element.
* It applies those limits if they are intended for the raw value.
*
* @param rawValue double containing the raw value that will be encoded
* if it turns out to be reasonable.
*
* @return boolean indicating if this function thinks the value is
* reasonable to fit in the allowable size and range.
*
*/
public boolean isFloatRawValueReasonable( final double rawValue ) {
// first find the general size applicable to the bit length
boolean minInclusive = true;
boolean maxInclusive = true;
double minValue = -Double.MAX_VALUE;
double maxValue = Double.MAX_VALUE;
// if a ValidRange element exists then we want to filter the min and
// max through that, but only if it applies to RAW
if ( validRange_.isValidRangeApplied() == true ) {
if ( validRange_.isLowValueCalibrated() == false ) {
minValue = Math.round( Double.parseDouble( validRange_.getLowValue() ) );
if ( validRange_.isLowValueInclusive() == false ) {
minInclusive = false;
}
}
if ( validRange_.isHighValueCalibrated() == false ) {
maxValue = Math.round( Double.parseDouble( validRange_.getHighValue() ) );
if ( validRange_.isHighValueInclusive() == false ) {
maxInclusive = false;
}
}
}
// check for the boundary conditions with the minimum first
if ( minInclusive == false ) {
if ( minValue >= rawValue ) {
warn( itemName_ + " Encoded value '" +
Double.toString( rawValue ) +
"' is too small for valid " +
"exclusive min value of '" +
Double.toString( minValue ) + "' on encoding of " +
rawTypeName_ );
return false;
}
} else {
if ( minValue > rawValue ) {
warn( itemName_ + " Encoded value '" +
Double.toString( rawValue ) +
"' is too small for valid " +
"inclusive min value of '" +
Double.toString( minValue ) + "' on encoding of " +
rawTypeName_ );
return false;
}
}
// check for the boundary conditions with the maximum
if ( maxInclusive == false ) {
if ( maxValue <= rawValue ) {
warn( itemName_ + " Encoded value '" +
Double.toString( rawValue ) +
"' is too large for valid " +
"exclusive max value of '" +
Double.toString( maxValue ) + "' on encoding of " +
rawTypeName_ );
return false;
}
} else {
if ( maxValue < rawValue ) {
warn( itemName_ + " Encoded value '" +
Double.toString( rawValue ) +
"' is too large for valid " +
"inclusive max value of '" +
Double.toString( maxValue ) + "' on encoding of " +
rawTypeName_ );
return false;
}
}
return true;
}
private void warn( final String warning ) {
if ( warnings_ == null ) {
warnings_ = new ArrayList<>();
}
warnings_.add( warning );
}
// Private Data Members
private String itemName_;
private EngineeringType euTypeName_;
private RawType rawTypeName_;
private int rawSizeInBits_;
private String rawBitOrder_;
private boolean validObject_;
private String booleanZeroString_;
private String booleanOneString_;
private List warnings_ = null;
private List enums_;
private CalibratorType defCal_;
private XTCEValidRange validRange_;
private XTCETypedObject itemObj_;
private XTCEAbsoluteTimeType timeHandler_ = null;
private static final byte[] utf16_ = new byte[] { (byte)0xfe, (byte)0xff };
}