/* ** CPQDIF_R_Observation class. Implements a PQDIF record "wrapper" for the ** data source record. You can NOT cast a standard record object to this ** class, because it has its own member data. ** -------------------------------------------------------------------------- ** ** File name: $Workfile: rec_observ.cpp $ ** Last modified: $Modtime: 12/01/00 12:45p $ ** Last modified by: $Author: Bill $ ** ** VCS archive path: $Archive: /Hank/DMM/FirmWare/Level3/ObDatMgr/rec_observ.cpp $ ** VCS revision: $Revision: 30 $ */ #include "PQDIF_classes.h" // Local functions // =============== // Function to round second values to the nearest nanosecond. inline double _FixSeconds(double dTime) { return floor( dTime * 1000000000.0 + 0.5 )/ 1000000000.0; } static void _AddSeconds( TIMESTAMPPQDIF &dt, double secondsToAdd ) { // Record the current day for an overflow check. DWORD dwDay = dt.day; // Perform the requested operation. dt.sec += secondsToAdd; // If the result is greater than the number of seconds in // a day then ... if( dt.sec > (double) SECONDS_PER_DAY ) { // Carry resulting number of days. long lDays = (long)( dt.sec / (double) SECONDS_PER_DAY ); dt.day += lDays; dt.sec -= ( lDays * (double) SECONDS_PER_DAY ); // Check for an overflow. if( dt.day < dwDay ) { dt.day = 0xffffffff; dt.sec = 86399.999999; } } // Else if the result is less than 0.0. else if( dt.sec < 0.0 ) { // Borrow the required number of days. long lDays = 1 - (long)( dt.sec / (double) SECONDS_PER_DAY ); dt.day -= lDays; dt.sec += ( lDays * (double) SECONDS_PER_DAY ); // Check for an underflow. if( dt.day > dwDay ) { dt.day = 0; dt.sec = 0.0; } } // Adjust the result. dt.sec = _FixSeconds( dt.sec ); } // Construction // ============ CPQDIF_R_Observation::CPQDIF_R_Observation() { m_pds = NULL; m_psett = NULL; m_record = NULL; } CPQDIF_R_Observation::CPQDIF_R_Observation( CPQDIFRecord& record ) { m_pds = NULL; m_psett = NULL; m_record = (CPQDIF_R_General *) &record; } CPQDIF_R_Observation::~CPQDIF_R_Observation() { // Don't destroy m_pds or m_record; these are only by reference, not by value. } bool CPQDIF_R_Observation::GetInfo ( TIMESTAMPPQDIF& timeStart, TIMESTAMPPQDIF& timeCreate, string& name ) { bool status; long countEntries = 0; CPQDIF_E_Scalar * psc; CPQDIF_E_Vector * pvect; // Init status = TRUE; memset( &timeStart, 0, sizeof( timeStart ) ); memset( &timeCreate, 0, sizeof( timeCreate ) ); name = ""; // First, find the times if( status ) { psc = FindScalarInCollection( m_record->m_pcollMain, tagTimeStart ); if( psc ) { status = psc->GetValueTimeStamp( timeStart ); } } if( status ) { psc = FindScalarInCollection( m_record->m_pcollMain, tagTimeCreate ); if( psc ) { status = psc->GetValueTimeStamp( timeCreate ); } } // Get name if( status ) { pvect = FindVectorInCollection( m_record->m_pcollMain, tagObservationName ); if( pvect ) { status = pvect->GetValues( name ); } } return status; } long CPQDIF_R_Observation::GetCountChannels( void ) { long count = 0; CPQDIF_E_Collection * pcolCI; pcolCI = GetChannelInstances(); if( pcolCI ) { count = pcolCI->GetCount(); } return count; } bool CPQDIF_R_Observation::GetTriggerInfo ( UINT4& idTriggerMethod, CPQDIF_E_Vector ** pvectTriggerChanIdx, TIMESTAMPPQDIF& timeTriggered ) { bool status = false; long countEntries = 0; CPQDIF_E_Scalar * psc; CPQDIF_E_Vector * pvect; // Init idTriggerMethod = ID_TRIGGER_METH_NONE; //ASSERT( pvectTriggerChanIdx ); *pvectTriggerChanIdx = NULL; memset( &timeTriggered, 0, sizeof( timeTriggered ) ); // First, find the trigger method psc = FindScalarInCollection( m_record->m_pcollMain, tagTriggerMethodID ); if( psc ) { status = psc->GetValueUINT4( idTriggerMethod ); } else { // Default to channel? NAHHH //status = TRUE; //idTriggerMethod = ID_TRIGGER_METH_CHANNEL; } // Get triggered channels? (NOT required; leave status alone) if( status && idTriggerMethod == ID_TRIGGER_METH_CHANNEL ) { pvect = FindVectorInCollection( m_record->m_pcollMain, tagChannelTriggerIdx ); if( pvect ) { // Validate physical type if( pvect->GetPhysicalType() == ID_PHYS_TYPE_UNS_INTEGER4 ) { // Return a pointer to the vector *pvectTriggerChanIdx = pvect; } } } // Get the time it was triggered if( status ) { status = false; psc = FindScalarInCollection( m_record->m_pcollMain, tagTimeTriggered ); if( psc ) { status = psc->GetValueTimeStamp( timeTriggered ); } } return status; } long CPQDIF_R_Observation::GetCountSeries( int idxChannel ) { long count = 0; CPQDIF_E_Collection * pcolOneChannel; CPQDIF_E_Collection * pcolSI; pcolOneChannel = GetOneChannel( idxChannel ); if( pcolOneChannel ) { pcolSI = GetSeriesInstances( pcolOneChannel ); if( pcolSI ) { count = pcolSI->GetCount(); } } return count; } bool CPQDIF_R_Observation::GetChannelInfo ( long idxChannel, string& name, UINT4& idPhase, GUID& idQuantityType, UINT4& idQuantityMeasured ) { bool status = true; long idxChannelDefn; // Find the channel defn index if( status ) { status = GetChannelDefnIdx( idxChannel, idxChannelDefn ); } // Gather information from the channel definitions if( status && m_pds ) { status = m_pds->GetChannelDefnInfo( idxChannelDefn, name, idPhase, idQuantityType, idQuantityMeasured ); } else { status = false; } return status; } bool CPQDIF_R_Observation::GetChannelPrimarySeries ( long idxChannel, long& idxPrimarySeries ) { bool status = true; long idxChannelDefn; // Find the channel defn index if( status ) { status = GetChannelDefnIdx( idxChannel, idxChannelDefn ); } // Gather information from the channel definitions if( status && m_pds ) { status = m_pds->GetChannelPrimarySeries( idxChannelDefn, idxPrimarySeries ); } else { status = false; } return status; } #ifdef zap // // // Depricated function // bool CPQDIF_R_Observation::GetChannelThresholds ( long idxChannel, UINT4& triggerTypeID, REAL8& fullScale, REAL8& noiseFloor, REAL8& triggerLow, REAL8& triggerHigh, REAL8& triggerRate, CPQDIF_E_Vector& triggerShapeParam // Array of [3] ) { bool status = false; long idxChannelDefn; bool found; long idxChannSett; long countChannSett; UINT4 idxChannelDefnSett; // DO we have settings? if( m_psett ) { // Determine which channel def'n is used for this channel // Find the channel defn index status = GetChannelDefnIdx( idxChannel, idxChannelDefn ); // Check all settings channels to see which matches the def'n if( status ) { // Init status = false; countChannSett = m_psett->GetCountChannels(); for( idxChannSett = 0; idxChannSett < countChannSett; idxChannSett++ ) { found = m_psett->GetChannelInfo( idxChannSett, idxChannelDefnSett, triggerTypeID, fullScale, noiseFloor, triggerLow, triggerHigh, triggerRate, triggerShapeParam ); // Is this the one that corresponds to the same def'n? if( found && idxChannelDefn == (long) idxChannelDefnSett ) { status = TRUE; break; } } // For( channel setting ) } // Found channel def'n } // Have settings return status; } #endif bool CPQDIF_R_Observation::GetSeriesInfo ( long idxChannel, long idxSeries, UINT4& idQuantityUnits, GUID& idQuantityCharacteristic, GUID& idValueType ) { bool status = true; long idxChannelDefn; UINT4 idStorageMethod; // Find the channel defn index if( status ) { status = GetChannelDefnIdx( idxChannel, idxChannelDefn ); } // Gather information from the series definition if( status && m_pds ) { status = m_pds->GetSeriesDefnInfo( idxChannelDefn, idxSeries, idQuantityUnits, idValueType, idQuantityCharacteristic, idStorageMethod ); } else { status = false; } return status; } long CPQDIF_R_Observation::AddChannel ( long idxChannelDefn ) { long idxNew = -1; CPQDIF_E_Collection * pcolInstances = GetChannelInstances(); CPQDIF_E_Collection * pcollOne; CPQDIF_E_Collection * pcollSeriesInstances; if( pcolInstances ) { // Get the new index idxNew = GetCountChannels(); // Create the new channel instance pcollOne = (CPQDIF_E_Collection *) theFactory.NewElement( ID_ELEMENT_TYPE_COLLECTION ); pcollOne->SetTag( tagOneChannelInst ); // Stuff in the information... pcollOne->SetScalarUINT4( tagChannelDefnIdx, idxChannelDefn ); // Also need a series instances collection pcollSeriesInstances = (CPQDIF_E_Collection *) theFactory.NewElement( ID_ELEMENT_TYPE_COLLECTION ); if( pcollSeriesInstances ) { pcollSeriesInstances->SetTag( tagSeriesInstances ); pcollOne->Add( pcollSeriesInstances ); } // Add it! pcolInstances->Add( pcollOne ); } return idxNew; } long CPQDIF_R_Observation::AddSeriesDouble ( long idxChannel, long countValues, double * arValues ) { long idxNew = -1; CPQDIF_E_Vector * pvectData; long idx; double * pValue; // Create vector for the series data pvectData = (CPQDIF_E_Vector *) theFactory.NewElement( ID_ELEMENT_TYPE_VECTOR ); if( pvectData ) { pvectData->SetTag( tagSeriesValues ); pvectData->SetPhysicalType( ID_PHYS_TYPE_REAL8 ); // Copy over series data pValue = arValues; pvectData->SetCount( countValues ); for( idx = 0; idx < countValues; idx++, pValue++ ) { pvectData->SetValue( idx, *pValue ); } // Add it ... idxNew = AddSeriesVector( idxChannel, pvectData ); // If it was not successful, delete the vector if( idxNew < 0 ) { delete pvectData; } } return idxNew; } long CPQDIF_R_Observation::AddSeriesVector ( long idxChannel, CPQDIF_E_Vector * pvectData ) { long idxNew = -1; CPQDIF_E_Collection * pcolOneChannel; CPQDIF_E_Collection * pcolSI; CPQDIF_E_Collection * pcollOne; pcolOneChannel = GetOneChannel( idxChannel ); if( pcolOneChannel && pvectData ) { pcolSI = GetSeriesInstances( pcolOneChannel ); if( pcolSI ) { // New channel index idxNew = pcolSI->GetCount(); // Create the new channel def'n pcollOne = (CPQDIF_E_Collection *) theFactory.NewElement( ID_ELEMENT_TYPE_COLLECTION ); if( pcollOne ) { // Set the tag for this collection ... pcollOne->SetTag( tagOneSeriesInstance ); // Make sure the vector has the right tag ... pvectData->SetTag( tagSeriesValues ); // The vector is currently the only member of this collection. pcollOne->Add( pvectData ); } // Add it! pcolSI->Add( pcollOne ); } } return idxNew; } long CPQDIF_R_Observation::AddSeriesShared ( long idxChannel, long idxChannelShared, long idxSeriesShared ) { long idxNew = -1; CPQDIF_E_Collection * pcolOneChannel; CPQDIF_E_Collection * pcolSI; CPQDIF_E_Collection * pcollOne; CPQDIF_E_Scalar * pscSharedChannel; CPQDIF_E_Scalar * pscSharedSeries; pcolOneChannel = GetOneChannel( idxChannel ); if( pcolOneChannel ) { pcolSI = GetSeriesInstances( pcolOneChannel ); if( pcolSI ) { // New channel index idxNew = pcolSI->GetCount(); // Create the new channel def'n pcollOne = (CPQDIF_E_Collection *) theFactory.NewElement( ID_ELEMENT_TYPE_COLLECTION ); if( pcollOne ) { // Set the tag for this collection ... pcollOne->SetTag( tagOneSeriesInstance ); // Create scalars which indicate which channel/series is to be shared pscSharedChannel = (CPQDIF_E_Scalar *) theFactory.NewElement( ID_ELEMENT_TYPE_SCALAR ); pscSharedSeries = (CPQDIF_E_Scalar *) theFactory.NewElement( ID_ELEMENT_TYPE_SCALAR ); if( pscSharedChannel && pscSharedSeries ) { // Tags & values pscSharedChannel->SetTag( tagSeriesShareChannelIdx ); pscSharedChannel->SetPhysicalType( ID_PHYS_TYPE_UNS_INTEGER4 ); pscSharedChannel->SetValueUINT4( idxChannelShared ); pscSharedSeries->SetTag( tagSeriesShareSeriesIdx ); pscSharedSeries->SetPhysicalType( ID_PHYS_TYPE_UNS_INTEGER4 ); pscSharedSeries->SetValueUINT4( idxSeriesShared ); // Stuff 'em pcollOne->Add( pscSharedChannel ); pcollOne->Add( pscSharedSeries ); } } // Add it! pcolSI->Add( pcollOne ); } } return idxNew; } bool CPQDIF_R_Observation::SetSeriesBaseQuantity ( long idxChannel, long idxSeries, double value ) { bool status = false; CPQDIF_E_Collection * pcol; CPQDIF_E_Scalar * psc; // Find the series pcol = GetOneSeries( idxChannel, idxSeries ); if( pcol ) { psc = FindScalarInCollection( pcol, tagSeriesBaseQuantity ); if( !psc ) { // Create it ! psc = (CPQDIF_E_Scalar *) theFactory.NewElement( ID_ELEMENT_TYPE_SCALAR ); if( psc ) { pcol->Add( psc ); } } // Init the scalar if( psc ) { psc->SetTag( tagSeriesBaseQuantity ); psc->SetValueREAL8( value ); status = TRUE; } } return status; } bool CPQDIF_R_Observation::SetSeriesScale ( long idxChannel, long idxSeries, double scale, double offset ) { bool status = false; CPQDIF_E_Collection * pcol; CPQDIF_E_Scalar * psc; #ifdef zap // Find the series pcol = GetOneSeries( idxChannel, idxSeries ); if( pcol ) { psc = FindOrCreateScalarInCollection( pcol, tagSeriesScale, ID_PHYS_TYPE_REAL8 ); if( psc ) { status = psc->SetValueREAL8( scale ); } psc = FindOrCreateScalarInCollection( pcol, tagSeriesOffset, ID_PHYS_TYPE_REAL8 ); if( psc ) { status = psc->SetValueREAL8( offset ); } } #endif // Find the series pcol = GetOneSeries( idxChannel, idxSeries ); if( pcol ) { psc = FindScalarInCollection( pcol, tagSeriesScale ); if( !psc ) { // Create it ! psc = (CPQDIF_E_Scalar *) theFactory.NewElement( ID_ELEMENT_TYPE_SCALAR ); if( psc ) { pcol->Add( psc ); } } // Init the scalar if( psc ) { psc->SetTag( tagSeriesScale ); psc->SetValueREAL8( scale ); status = TRUE; } psc = FindScalarInCollection( pcol, tagSeriesOffset ); if( !psc ) { // Create it ! psc = (CPQDIF_E_Scalar *) theFactory.NewElement( ID_ELEMENT_TYPE_SCALAR ); if( psc ) { pcol->Add( psc ); } } // Init the scalar if( psc ) { psc->SetTag( tagSeriesOffset ); psc->SetValueREAL8( offset ); status = TRUE; } } return status; } bool CPQDIF_R_Observation::GetSeriesBaseQuantity ( long idxChannel, long idxSeries, double& value ) { bool status = false; CPQDIF_E_Collection * pcol; CPQDIF_E_Scalar * psc; // Find the series pcol = GetOneSeries( idxChannel, idxSeries ); if( pcol ) { psc = FindScalarInCollection( pcol, tagSeriesBaseQuantity ); if( psc ) { status = psc->GetValueREAL8( value ); } } return status; } #ifdef PQDIF_USE_COM bool CPQDIF_R_Observation::GetObservationExtendedData ( GUID& gidTag, VARIANT& value ) { bool status = false; CPQDIF_E_Scalar * psc; psc = FindScalarInCollection( m_record->m_pcollMain, gidTag ); if( psc ) { status = psc->GetValue( value ); } return status; } bool CPQDIF_R_Observation::GetSeriesExtendedData ( long idxChannel, long idxSeries, GUID& gidTag, VARIANT& value ) { bool status = false; CPQDIF_E_Collection * pcollOneChannel; CPQDIF_E_Scalar * psc; pcollOneChannel = GetOneSeries( idxChannel, idxSeries ); if (pcollOneChannel) { psc = FindScalarInCollection( pcollOneChannel, gidTag ); if( psc ) { status = psc->GetValue( value ); } } return status; } bool CPQDIF_R_Observation::GetChannelExtendedData ( long idxChannel, GUID& gidTag, VARIANT& value ) { bool status = false; CPQDIF_E_Collection * pcollOneChannel; CPQDIF_E_Scalar * psc; pcollOneChannel = GetOneChannel( idxChannel ); if (pcollOneChannel) { psc = FindScalarInCollection( pcollOneChannel, gidTag ); if( psc ) { status = psc->GetValue( value ); } } return status; } #endif bool CPQDIF_R_Observation::GetSeriesDefnNominal ( long idxChannel, long idxSeries, double & dNominal ) { bool status = false; long idxChannelDefn; status = GetChannelDefnIdx( idxChannel, idxChannelDefn ); if (m_pds) { status = m_pds->GetSeriesDefnNominal(idxChannelDefn, idxSeries, dNominal); } return status; } bool CPQDIF_R_Observation::GetSeriesDefnPrecisionAndResolution ( long idxChannel, long idxSeries, UINT4 & uPrecision, double & dResolution ) { bool status = false; long idxChannelDefn; status = GetChannelDefnIdx( idxChannel, idxChannelDefn ); if (m_pds) { status = m_pds->GetSeriesDefnPrecisionAndResolution(idxChannelDefn, idxSeries, uPrecision, dResolution); } return status; } bool CPQDIF_R_Observation::GetSeriesScale ( long idxChannel, long idxSeries, double& scale, double& offset ) { bool status = false; CPQDIF_E_Collection * pcol; CPQDIF_E_Scalar * psc; // Find the series pcol = GetOneSeries( idxChannel, idxSeries ); if( pcol ) { psc = FindScalarInCollection( pcol, tagSeriesScale ); if( psc ) { status = psc->GetValueREAL8( scale ); } psc = FindScalarInCollection( pcol, tagSeriesOffset ); if( psc ) { status = psc->GetValueREAL8( offset ); } } return status; } CPQDIF_E_Vector * CPQDIF_R_Observation::GetSeriesValueVector ( long idxChannel, long idxSeries ) { CPQDIF_E_Vector * pvectReturn = NULL; CPQDIF_E_Collection * pcolOneSeries; pcolOneSeries = GetOneSeries( idxChannel, idxSeries ); if( pcolOneSeries ) { pvectReturn = FindVectorInCollection( pcolOneSeries, tagSeriesValues ); } return pvectReturn; } bool CPQDIF_R_Observation::SetTimeCreateAndTimeStart ( const TIMESTAMPPQDIF& timeCreate, const TIMESTAMPPQDIF& timeStart ) { bool status = false; CPQDIF_E_Scalar * psc; CPQDIF_E_Vector * pvect; // Init //ASSERT(aidxTriggerChan); // First, find (or create) the trigger method psc = FindOrCreateScalarInCollection(m_record->m_pcollMain, tagTimeCreate, ID_PHYS_TYPE_TIMESTAMPPQDIF); // Set its value if (psc) { status = psc->SetValueTimeStamp(timeCreate); } // Set the time it was triggered if (status) { status = false; psc = FindOrCreateScalarInCollection(m_record->m_pcollMain, tagTimeStart, ID_PHYS_TYPE_TIMESTAMPPQDIF); // Set value if (psc) { status = psc->SetValueTimeStamp(timeStart); } } return status; } bool CPQDIF_R_Observation::SetTriggerInfo ( UINT4 idTriggerMethod, long countTriggers, const UINT4 * aidxTriggerChan, const TIMESTAMPPQDIF& timeTriggered ) { bool status = false; CPQDIF_E_Scalar * psc; CPQDIF_E_Vector * pvect; // Init //ASSERT( aidxTriggerChan ); // First, find (or create) the trigger method psc = FindOrCreateScalarInCollection( m_record->m_pcollMain, tagTriggerMethodID, ID_PHYS_TYPE_UNS_INTEGER4 ); // Set its value if( psc ) { status = psc->SetValueUINT4( idTriggerMethod ); } // Get triggered channels? if( status && idTriggerMethod == ID_TRIGGER_METH_CHANNEL ) { status = false; pvect = FindOrCreateVectorInCollection( m_record->m_pcollMain, tagChannelTriggerIdx, ID_PHYS_TYPE_UNS_INTEGER4 ); // Set its value(s) if( pvect ) { // Validate physical type if( pvect->GetPhysicalType() == ID_PHYS_TYPE_UNS_INTEGER4 ) { pvect->SetCount( countTriggers ); for( long idx = 0; idx < countTriggers; idx++ ) { pvect->SetValueUINT4( idx, aidxTriggerChan[ idx ] ); } status = TRUE; } } } // Set the time it was triggered if( status ) { status = false; psc = FindOrCreateScalarInCollection( m_record->m_pcollMain, tagTimeTriggered, ID_PHYS_TYPE_TIMESTAMPPQDIF ); // Set value if( psc ) { status = psc->SetValueTimeStamp( timeTriggered ); } } return status; } long CPQDIF_R_Observation::GetCountResolvedSeries ( long idxChannel, long idxSeries, bool noShare ) { int idx; bool status = false; long countPoints = 0; long idxChannelDefn; UINT4 idQuantityUnits; GUID idQuantityCharacteristic; GUID idValueType; UINT4 idStorageMethod; bool gotShareChannel = false; bool gotShareSeries = false; UINT4 idxShareChannelIdx = 0; UINT4 idxShareSeriesIdx = 0; CPQDIF_Element * pel = NULL; CPQDIF_E_Collection * pcol = NULL; CPQDIF_E_Vector * pvectSeriesArray = NULL; // Verify that we're in an observation record // Requires a data source record if( m_record && m_pds && idxChannel >= 0 && idxSeries >= 0) { // Find the channel defn index status = GetChannelDefnIdx( idxChannel, idxChannelDefn ); // Fail if we got a bogus index if( status && idxChannelDefn < 0 ) status = false; } // Get the storage method if( status ) { status = m_pds->GetSeriesDefnInfo( idxChannelDefn, idxSeries, idQuantityUnits, idValueType, idQuantityCharacteristic, idStorageMethod ); } // Look for shared channel and series indices, or a vector of values if( status ) { // Find the series pcol = GetOneSeries( idxChannel, idxSeries ); if( pcol ) { status = true; for( idx = 0; idx < pcol->GetCount(); idx++ ) { pel = pcol->GetElement( idx ); if( pel ) { if( pel->GetElementType() == ID_ELEMENT_TYPE_SCALAR ) { CPQDIF_E_Scalar *psc = (CPQDIF_E_Scalar *) pel; if( PQDIF_IsEqualGUID( pel->GetTag(), tagSeriesShareChannelIdx ) ) { gotShareChannel = TRUE; psc->GetValueUINT4( idxShareChannelIdx ); if( gotShareSeries ) break; } if( PQDIF_IsEqualGUID( pel->GetTag(), tagSeriesShareSeriesIdx ) ) { gotShareSeries = TRUE; psc->GetValueUINT4( idxShareSeriesIdx ); if( gotShareChannel ) break; } } else if( pel->GetElementType() == ID_ELEMENT_TYPE_VECTOR && PQDIF_IsEqualGUID( pel->GetTag(), tagSeriesValues ) ) { pvectSeriesArray = (CPQDIF_E_Vector *) pel; break; } } } } } // Now count the values if( status ) { if( gotShareChannel && gotShareSeries ) { // We're sharing the series from somwhere else -- // generate it from the shared indices if( !noShare ) { countPoints = GetCountResolvedSeries( (long) idxShareChannelIdx, (long) idxShareSeriesIdx, true ); // recurse only once } } else if( pvectSeriesArray ) { // Generate the new series array countPoints = _GenerateSeriesCount( idStorageMethod, pvectSeriesArray); } } return countPoints; } BOOL CPQDIF_R_Observation::GetSeriesBaseType ( long idxChannel, long idxSeries, long& nSeriesBaseType ) { BOOL status = FALSE; int idx; CPQDIF_Element * pel; CPQDIF_E_Collection * pcol; CPQDIF_E_Scalar * psc; CPQDIF_E_Vector * pvectSeriesArray; long typePhysical; PQDIFValue value; double valueReal; double rBaseValue = 1.0; double rScale = 1.0; double rOffset = 0.0; bool gotShareChannel = false; bool gotShareSeries = false; bool isShared = false; UINT4 idxShareChannelIdx = 0; UINT4 idxShareSeriesIdx = 0; pcol = GetOneSeries( idxChannel, idxSeries ); if( pcol ) { status = TRUE; // Loop through all elements in the series collection for( idx = 0; idx < pcol->GetCount(); idx++ ) { pel = pcol->GetElement( idx ); if( pel ) { if( pel->GetElementType() == ID_ELEMENT_TYPE_SCALAR ) { psc = (CPQDIF_E_Scalar *) pel; // If it's REAL4 or REAL8, go ahead and pull it out valueReal = 0.0; psc->GetValue( typePhysical, value ); nSeriesBaseType = typePhysical; } if( pel->GetElementType() == ID_ELEMENT_TYPE_VECTOR && PQDIF_IsEqualGUID( pel->GetTag(), tagSeriesValues ) ) { pvectSeriesArray = (CPQDIF_E_Vector *) pel; nSeriesBaseType = pvectSeriesArray->GetPhysicalType(); } } // if( pel ) } } return status; } double * CPQDIF_R_Observation::NewResolvedSeries ( long idxChannel, long idxSeries, long& countPoints, bool noShare ) { bool status = false; int idx; double * arValues = NULL; CPQDIF_Element * pel = NULL; CPQDIF_E_Collection * pcol = NULL; CPQDIF_E_Scalar * psc = NULL; CPQDIF_E_Vector * pvectSeriesArray = NULL; long typePhysical; PQDIFValue value; double valueReal; double rBaseValue = 1.0; double rScale = 1.0; double rOffset = 0.0; long idxChannelDefn = 0; string name; UINT4 idPhase; GUID idQuantityType; UINT4 idQuantityMeasured; UINT4 idQuantityUnits; GUID idQuantityCharacteristic; GUID idValueType; UINT4 idStorageMethod; bool gotShareChannel = false; bool gotShareSeries = false; bool isShared = false; UINT4 idxShareChannelIdx = 0; UINT4 idxShareSeriesIdx = 0; // Verify that we're in an observation record // Requires a data source record if( m_record && m_pds && idxChannel >= 0 && idxSeries >= 0) { // Find the channel defn index status = GetChannelDefnIdx( idxChannel, idxChannelDefn ); // Fail if we got a bogus index if( status && idxChannelDefn < 0 ) status = false; } // Gather information from the channel & series definitions if( status ) { status = m_pds->GetChannelDefnInfo( idxChannelDefn, name, idPhase, idQuantityType, idQuantityMeasured ); } if( status ) { status = m_pds->GetSeriesDefnInfo( idxChannelDefn, idxSeries, idQuantityUnits, idValueType, idQuantityCharacteristic, idStorageMethod ); } if( status ) { status = false; // Find the series pcol = GetOneSeries( idxChannel, idxSeries ); if( pcol ) { status = true; // Loop through all elements in the series collection for( idx = 0; idx < pcol->GetCount(); idx++ ) { pel = pcol->GetElement( idx ); if( pel ) { if( pel->GetElementType() == ID_ELEMENT_TYPE_SCALAR ) { psc = (CPQDIF_E_Scalar *) pel; // If it's REAL4 or REAL8, go ahead and pull it out valueReal = 0.0; psc->GetValue( typePhysical, value ); if (typePhysical == ID_PHYS_TYPE_INTEGER4) { valueReal = value.int4; } if( typePhysical == ID_PHYS_TYPE_REAL4 ) { valueReal = value.real4; } if( typePhysical == ID_PHYS_TYPE_REAL8 ) { valueReal = value.real8; } if( PQDIF_IsEqualGUID( pel->GetTag(), tagSeriesBaseQuantity ) ) { rBaseValue = valueReal; } if( PQDIF_IsEqualGUID( pel->GetTag(), tagSeriesScale ) ) { rScale = valueReal; } if( PQDIF_IsEqualGUID( pel->GetTag(), tagSeriesOffset ) ) { rOffset = valueReal; } if( PQDIF_IsEqualGUID( pel->GetTag(), tagSeriesShareChannelIdx ) ) { gotShareChannel = TRUE; psc->GetValueUINT4( idxShareChannelIdx ); } if( PQDIF_IsEqualGUID( pel->GetTag(), tagSeriesShareSeriesIdx ) ) { gotShareSeries = TRUE; psc->GetValueUINT4( idxShareSeriesIdx ); } } if( pel->GetElementType() == ID_ELEMENT_TYPE_VECTOR && PQDIF_IsEqualGUID( pel->GetTag(), tagSeriesValues ) ) { pvectSeriesArray = (CPQDIF_E_Vector *) pel; } } // if( pel ) } } } // Generate the series data if( status ) { if( gotShareChannel && gotShareSeries ) { // We're sharing the series from somwhere else -- // generate it from the shared indices if( !noShare ) { arValues = NewResolvedSeries( (long) idxShareChannelIdx, (long) idxShareSeriesIdx, countPoints, true ); } else { // Can't generate! The file is trying to share a series // from another shared series. This is not legal. arValues = NULL; } } else if( pvectSeriesArray ) { // Generate the new series array arValues = _GenerateSeriesData( idxChannelDefn, idStorageMethod, rBaseValue, rScale, rOffset, pvectSeriesArray, countPoints ); } else { // Can't generate! arValues = NULL; } } return arValues; } TIMESTAMPPQDIF * CPQDIF_R_Observation::NewResolvedSeriesTimeStamp ( long idxChannel, long idxSeries, long& countPoints, bool noShare ) { TIMESTAMPPQDIF * result = NULL; CPQDIF_E_Collection * pcol; CPQDIF_Element * pel; CPQDIF_E_Scalar * psc; CPQDIF_E_Vector * pvectSeriesArray; // Shared? BOOL gotShareChannel = FALSE; BOOL gotShareSeries = FALSE; UINT4 idxShareChannelIdx = 0; UINT4 idxShareSeriesIdx = 0; pcol = GetOneSeries( idxChannel, idxSeries ); if( pcol ) { // Is this sucker shared? pel = pcol->GetElement( tagSeriesShareChannelIdx ); if( pel && pel->GetElementType() == ID_ELEMENT_TYPE_SCALAR ) { gotShareChannel = TRUE; psc = static_cast( pel ); psc->GetValueUINT4( idxShareChannelIdx ); } pel = pcol->GetElement( tagSeriesShareSeriesIdx ); if( pel && pel->GetElementType() == ID_ELEMENT_TYPE_SCALAR ) { gotShareSeries = TRUE; psc = static_cast( pel ); psc->GetValueUINT4( idxShareSeriesIdx ); } if( gotShareSeries && gotShareSeries && !noShare ) { // SHARED. // Allow ONE level of recursion -- no more. result = NewResolvedSeriesTimeStamp( idxShareChannelIdx, idxShareSeriesIdx, countPoints, true ); } else { // NOT SHARED. // Try to decode it the normal way. pel = pcol->GetElement( tagSeriesValues ); if( pel->GetElementType() == ID_ELEMENT_TYPE_VECTOR ) { pvectSeriesArray = static_cast( pel ); // Determine size/allocate space for the timestamp array if( pvectSeriesArray->GetCount( countPoints ) ) { result = new TIMESTAMPPQDIF[ countPoints ]; if( result ) { // Is it already in timestamp form? if( pvectSeriesArray->GetPhysicalType() == ID_PHYS_TYPE_TIMESTAMPPQDIF ) { // We're done! countPoints = pvectSeriesArray->GetValuesTimeStamp ( result, countPoints ); } else { // Fabricate it from starting time stamp and second offsets double * seconds = NewResolvedSeries( idxChannel, idxSeries, countPoints, true ); if( seconds ) { _GenerateTimeStampArray( result, seconds, countPoints ); delete [] seconds; } } } } } } } return result; } bool CPQDIF_R_Observation::GetChannelDefnIdx ( long idxChannel, long& idxChannelDefn ) { bool status = false; CPQDIF_E_Collection * pcollOneChannel; CPQDIF_E_Scalar * psc; UINT4 idx; // Init status = false; idxChannelDefn = 0; // Find the channel pcollOneChannel = GetOneChannel( idxChannel ); if( pcollOneChannel ) { // This is where the index should be psc = m_record->FindScalarInCollection( pcollOneChannel, tagChannelDefnIdx ); if( psc ) { status = psc->GetValueUINT4( idx ); idxChannelDefn = (long) idx; status = TRUE; } } return status; } CPQDIF_E_Collection * CPQDIF_R_Observation::GetChannelInstances( void ) { CPQDIF_E_Collection * pcollChannels; // Create the collection if it does not yet exist. pcollChannels = m_record->FindCollectionInCollection( m_record->m_pcollMain, tagChannelInstances ); if( !pcollChannels ) { pcollChannels = (CPQDIF_E_Collection *) theFactory.NewElement( ID_ELEMENT_TYPE_COLLECTION ); if( pcollChannels ) { pcollChannels->SetTag( tagChannelInstances ); m_record->m_pcollMain->Add( pcollChannels ); } } return pcollChannels; } CPQDIF_E_Collection * CPQDIF_R_Observation::GetOneChannel( long idxChannel ) { CPQDIF_E_Collection * pcolReturn = NULL; CPQDIF_E_Collection * pcolInstances = GetChannelInstances(); CPQDIF_Element * pel; if( pcolInstances ) { pel = pcolInstances->GetElement( idxChannel ); if( pel ) { if( pel->GetElementType() == ID_ELEMENT_TYPE_COLLECTION && PQDIF_IsEqualGUID( pel->GetTag(), tagOneChannelInst ) ) { pcolReturn = (CPQDIF_E_Collection *) pel; } } } return pcolReturn; } CPQDIF_E_Collection * CPQDIF_R_Observation::GetSeriesInstances ( CPQDIF_E_Collection * pcolChannel ) { return m_record->FindCollectionInCollection( pcolChannel, tagSeriesInstances ); } CPQDIF_E_Collection * CPQDIF_R_Observation::GetOneSeries ( CPQDIF_E_Collection * pcolChannel, long idxSeries ) { CPQDIF_E_Collection * pcolReturn = NULL; CPQDIF_E_Collection * pcolSeriesInstances = NULL; CPQDIF_Element * pel; if( pcolChannel ) { // Get the series instances for this channel instance pcolSeriesInstances = GetSeriesInstances( pcolChannel ); if( pcolSeriesInstances ) { // Find the specific series instance pel = pcolSeriesInstances->GetElement( idxSeries ); if( pel ) { if( pel->GetElementType() == ID_ELEMENT_TYPE_COLLECTION && PQDIF_IsEqualGUID( pel->GetTag(), tagOneSeriesInstance ) ) { // Return it! pcolReturn = (CPQDIF_E_Collection *) pel; } } } } return pcolReturn; } CPQDIF_E_Collection * CPQDIF_R_Observation::GetOneSeries ( long idxChannel, long idxSeries ) { CPQDIF_E_Collection * pcolReturn = NULL; CPQDIF_E_Collection * pcolOneChannel = NULL; pcolOneChannel = GetOneChannel( idxChannel ); pcolReturn = GetOneSeries( pcolOneChannel, idxSeries ); return pcolReturn; } long CPQDIF_R_Observation::_GenerateSeriesCount ( UINT4 idStorageMethod, CPQDIF_E_Vector * pvectSeriesArray ) { long countPoints = 0; if( idStorageMethod & ID_SERIES_METHOD_VALUES ) { // Straight vector. pvectSeriesArray->GetCount( countPoints ); } else if( idStorageMethod & ID_SERIES_METHOD_INCREMENT ) { // Incremental storage method ... some assembly required. long countValues; long idxValue; double rCount; // Read in the rate change list pvectSeriesArray->GetCount( countValues ); if( countValues > 0 ) { // Grab only the point counts at indices 1, 3, 5, ... for( idxValue = 1; idxValue < countValues; idxValue += 2 ) { pvectSeriesArray->GetValue( idxValue, rCount ); countPoints += (long) rCount; } } } else { // No third option! } return countPoints; } double * CPQDIF_R_Observation::_GenerateSeriesData ( int idxChannelDefn, UINT4 idStorageMethod, double rBaseValue, double rScale, double rOffset, CPQDIF_E_Vector * pvectSeriesArray, long& countPoints ) { double * arValues = NULL; double * prTempValues; long idxPoint; long countValues; long idxValue; bool useScale = false; bool useCal = false; // Unused parameter rBaseValue = rBaseValue; // Get raw number of values in the vector. This may be the actual // number of points. pvectSeriesArray->GetCount( countValues ); // Determine how many total points countPoints = _GenerateSeriesCount( idStorageMethod, pvectSeriesArray ); if( idStorageMethod & ID_SERIES_METHOD_VALUES ) { // Straight vector. No assembly necessary. // The two counts must be identical. if( countPoints > 0 && countPoints == countValues ) { // We already have the number of points... arValues = new double[ countPoints ]; prTempValues = arValues; for( idxPoint = 0; idxPoint < countPoints; idxPoint++, prTempValues++ ) { pvectSeriesArray->GetValue( idxPoint, *prTempValues ); } } } else if( idStorageMethod & ID_SERIES_METHOD_INCREMENT ) { // Incremental storage method ... some assembly required. double valueNext; double rCount; double rRate ; long countChanges; long idxChange; long countPointsThisChange; // Go through the rate change list and generate the array. if( countPoints > 0 ) { arValues = new double[ countPoints ]; if( arValues ) { // Init -- get ready for loops prTempValues = arValues; valueNext = 0.0; // First item will be zero // Determine total number of rate changes [0] pvectSeriesArray->GetValue( 0, rCount ); countChanges = (long) rCount; // Get counts and rate changes ... for( idxChange = 0; idxChange < countChanges; idxChange++ ) { // Calculate index into value array ... idxValue = ( idxChange * 2 ) + 1; // Get data ... pvectSeriesArray->GetValue( idxValue + 0, rCount ); // Count @ rate pvectSeriesArray->GetValue( idxValue + 1, rRate ); // Rate countPointsThisChange = (long) rCount; // Generate points from the data ... for( idxPoint = 0; idxPoint < countPointsThisChange; idxPoint++, prTempValues++ ) { // Store current point. *prTempValues = valueNext; // Calculate next point. valueNext += rRate; } // for( points ); } // for( changes ) } } } else { // No third option! arValues = NULL; } // Scale & offset? if( idStorageMethod & ID_SERIES_METHOD_SCALED ) { // Scale/offset should already be set. useScale = true; } else { // Default values for scale/offset rScale = 1.0; rOffset = 0.0; useScale = false; } // CT/PT ratios? useCal = _GetCalibrationRatio( idxChannelDefn, rScale ); if( useCal ) { // The scale has now been adjusted to apply // the calibration ratio. useScale = true; } // Adjust, if necessary. if( useScale ) { if( arValues && countPoints > 0 ) { prTempValues = arValues; for( idxPoint = 0; idxPoint < countPoints; idxPoint++, prTempValues++ ) { // Apply scale first, then offset *prTempValues *= rScale; *prTempValues += rOffset; } // for( points ); } } return arValues; } bool CPQDIF_R_Observation::_GenerateTimeStampArray ( TIMESTAMPPQDIF * result, double * seconds, long countPoints ) { bool status = false; TIMESTAMPPQDIF tsStart; TIMESTAMPPQDIF tsTemp; string name; TIMESTAMPPQDIF * resTemp = result; double * secTemp = seconds; // Get start time for the entire observation. If successful then ... status = GetInfo( tsStart, tsTemp, name ); if (tsStart.day > 0) status = 1; if( status ) { // For each value do ... for( int idx = 0; idx < countPoints; idx++, resTemp++, secTemp++ ) { // Get starting time *resTemp = tsStart; // Add seconds to it _AddSeconds( *resTemp, *secTemp ); } // for( stamps ) } return status; } bool CPQDIF_R_Observation::_GetCalibrationRatio ( int idxChannelDefn, double& rScale ) { bool status = false; if( m_psett ) { TIMESTAMPPQDIF tsTemp; bool useCal = false; bool useTrans = false; // Not used bool gotInfo = m_psett->GetInfo( tsTemp, tsTemp, tsTemp, useCal, useTrans ); if( gotInfo && useCal ) { long countChannels; countChannels = m_psett->GetCountChannels(); for( long idxChannel = 0; idxChannel < countChannels; idxChannel++ ) { UINT4 idxChannelDefnCurrent; gotInfo = m_psett->GetChannelInfo( idxChannel, idxChannelDefnCurrent); if( gotInfo ) { // Is this the information for the correct channel defn? if( idxChannelDefn == (int) idxChannelDefnCurrent ) { UINT4 xdTransformerTypeID; REAL8 xdSystemSideRatio; REAL8 xdMonitorSideRatio; CPQDIF_E_Vector xdFrequencyResponse; gotInfo = m_psett->GetChanTrans( idxChannel, xdTransformerTypeID, xdSystemSideRatio, xdMonitorSideRatio, xdFrequencyResponse ); if( gotInfo ) { // Looks like we got it... rScale *= xdMonitorSideRatio; rScale /= xdSystemSideRatio; status = true; break; } } } } } } return status; }