#include #include #include "logvar.h" #include "debug.h" #define GET_BOOL_VAL(p, m) (!!(*p & m)) #define SET_BIT(p, m) (*p |= m) #define CLR_BIT(p, m) (*p &= ~m) #define STORE_BIT(p, m, b) (b) ? SET_BIT(p, m) : CLR_BIT(p, m) ///////////////////////////////////////////////////////////////////////////// CLogVariable::CLogVariable(LogTypes lt, void *pData, bool *pbLogCond, const std::type_info &rti, HSHM hShm, const char *pszName, int nIndex, CLoggable *pParent) : m_lt(lt), m_pbLogCond(pbLogCond), m_bOldLogCond(false), m_name(pszName), m_pszPath(NULL), m_nIndex(nIndex), m_vt(VT_Invalid), m_data({NULL}), m_fLastSample(0), m_fSamples(0), m_pParent(pParent), m_nUpdates(0), m_nTagID(0), m_nSampleCount(0), m_pnCvByte(NULL), m_nCvMask(0), m_bCvIsBit(false), m_bIsDbPersistant(_IS_DB_PERSISTENT_LOGTYPE(lt)) { if(!pData || !hShm) { ASSERT(false); } m_bIsCondLog = _IS_CONDITIONAL_LOGTYPE(m_lt); m_bIsIntervalLog = _IS_INTERVAL_LOGTYPE(m_lt); if(m_bIsCondLog && !m_pbLogCond) { ASSERT(false); } m_data.pVoid = pData; m_hShm = hShm; m_fMin = std::numeric_limits::infinity(); m_fMax = -std::numeric_limits::infinity(); if(rti == typeid(bool)) { m_vt = VT_bool; m_cache.boolVal = *m_data.pBool; } else if(rti == typeid(char)) { #ifdef __CHAR_UNSIGNED__ m_vt = VT_UI1; m_cache.UI1Val = *m_data.pUI1; #else m_vt = VT_I1; m_cache.I1Val = *m_data.pI1; #endif } else if(rti == typeid(signed char)) { m_vt = VT_I1; m_cache.I1Val = *m_data.pI1; } else if(rti == typeid(unsigned char)) { m_vt = VT_UI1; m_cache.UI1Val = *m_data.pUI1; } else if(rti == typeid(short)) { m_vt = VT_I2; m_cache.I2Val = *m_data.pI2; } else if(rti == typeid(unsigned short)) { m_vt = VT_UI2; m_cache.UI2Val = *m_data.pUI2; } else if(rti == typeid(int)) { m_vt = VT_I4; m_cache.I4Val = *m_data.pI4; } else if(rti == typeid(unsigned int)) { m_vt = VT_UI4; m_cache.UI4Val = *m_data.pUI4; } else if(rti == typeid(long)) { if(sizeof(long) == sizeof(long long)) { m_vt = VT_I8; m_cache.I8Val = *m_data.pI8; } else { m_vt = VT_I4; m_cache.I4Val = *m_data.pI4; } } else if(rti == typeid(unsigned long)) { if(sizeof(unsigned long) == sizeof(unsigned long long)) { m_vt = VT_UI8; m_cache.UI8Val = *m_data.pUI8; } else { m_vt = VT_UI4; m_cache.UI4Val = *m_data.pUI4; } } else if(rti == typeid(long long)) { m_vt = VT_I8; m_cache.I8Val = *m_data.pI8; } else if(rti == typeid(unsigned long long)) { m_vt = VT_UI8; m_cache.UI8Val = *m_data.pUI8; } else if(rti == typeid(float)) { m_vt = VT_float; m_cache.FloatVal = *m_data.pFloat; } else if(rti == typeid(double)) { m_vt = VT_double; m_cache.DoubleVal = *m_data.pDouble; } else { ASSERT(false); } } CLogVariable::CLogVariable(LogTypes lt, void *pData, void *pBase, size_t nCvOffset, unsigned int nCvBitNr, const std::type_info &rti, HSHM hShm, const char *pszName, int nIndex, CLoggable *pParent) : m_lt(lt), m_bOldLogCond(false), m_name(pszName), m_pszPath(NULL), m_nIndex(nIndex), m_fLastSample(0), m_fSamples(0), m_pParent(pParent), m_nUpdates(0), m_nTagID(0), m_nSampleCount(0), m_bCvIsBit(true), m_bIsDbPersistant(_IS_DB_PERSISTENT_LOGTYPE(lt)) { if(!pData || !hShm || nCvBitNr > 7) { ASSERT(false); } m_bIsCondLog = _IS_CONDITIONAL_LOGTYPE(m_lt); m_bIsIntervalLog = _IS_INTERVAL_LOGTYPE(m_lt); m_data.pVoid = pData; m_hShm = hShm; m_fMin = std::numeric_limits::infinity(); m_fMax = -std::numeric_limits::infinity(); m_pnCvByte = (uint8_t*)pBase + nCvOffset; m_nCvMask = 0x01 << nCvBitNr; if(rti == typeid(bool)) { m_vt = VT_bool; m_cache.boolVal = *m_data.pBool; } else if(rti == typeid(char)) { #ifdef __CHAR_UNSIGNED__ m_vt = VT_UI1; m_cache.UI1Val = *m_data.pUI1; #else m_vt = VT_I1; m_cache.I1Val = *m_data.pI1; #endif } else if(rti == typeid(signed char)) { m_vt = VT_I1; m_cache.I1Val = *m_data.pI1; } else if(rti == typeid(unsigned char)) { m_vt = VT_UI1; m_cache.UI1Val = *m_data.pUI1; } else if(rti == typeid(short)) { m_vt = VT_I2; m_cache.I2Val = *m_data.pI2; } else if(rti == typeid(unsigned short)) { m_vt = VT_UI2; m_cache.UI2Val = *m_data.pUI2; } else if(rti == typeid(int)) { m_vt = VT_I4; m_cache.I4Val = *m_data.pI4; } else if(rti == typeid(unsigned int)) { m_vt = VT_UI4; m_cache.UI4Val = *m_data.pUI4; } else if(rti == typeid(long)) { if(sizeof(long) == sizeof(long long)) { m_vt = VT_I8; m_cache.I8Val = *m_data.pI8; } else { m_vt = VT_I4; m_cache.I4Val = *m_data.pI4; } } else if(rti == typeid(unsigned long)) { if(sizeof(unsigned long) == sizeof(unsigned long long)) { m_vt = VT_UI8; m_cache.UI8Val = *m_data.pUI8; } else { m_vt = VT_UI4; m_cache.UI4Val = *m_data.pUI4; } } else if(rti == typeid(long long)) { m_vt = VT_I8; m_cache.I8Val = *m_data.pI8; } else if(rti == typeid(unsigned long long)) { m_vt = VT_UI8; m_cache.UI8Val = *m_data.pUI8; } else if(rti == typeid(float)) { m_vt = VT_float; m_cache.FloatVal = *m_data.pFloat; } else if(rti == typeid(double)) { m_vt = VT_double; m_cache.DoubleVal = *m_data.pDouble; } else { ASSERT(false); } } CLogVariable::~CLogVariable(void) { } ///////////////////////////////////////////////////////////////////////////// void CLogVariable::InitPath(CLoggable *pParent, const char *pszMemberName) { if(!pszMemberName) pszMemberName = ""; if(pParent) { m_path = pParent->GetPath(); m_path += "/"; m_path += pszMemberName; if(m_nIndex >= 0) { char szIndex[32]; sprintf(szIndex, "[%d]", m_nIndex); m_path += szIndex; } } else { m_path = pszMemberName; } m_pszPath = m_path.c_str(); } ///////////////////////////////////////////////////////////////////////////// void CLogVariable::InitTagID(CDataLogger &rdl) { if((m_nTagID = rdl.GetTagID(m_pszPath, (int)m_vt, (int)m_lt)) == ULONG_MAX) { ASSERT(false); } } ///////////////////////////////////////////////////////////////////////////// bool CLogVariable::CanLog(bool fLock) { if(!m_bIsCondLog) return true; bool bRet; if(fLock) Lock(); if(m_bCvIsBit) bRet = GET_BOOL_VAL(m_pnCvByte, m_nCvMask); else bRet = *m_pbLogCond; if(fLock) Unlock(); return bRet; } ///////////////////////////////////////////////////////////////////////////// void CLogVariable::Sample(void) { if(!m_bIsIntervalLog) return; if(!CanLog(true)) return; Lock(); switch(m_vt) { case VT_bool: m_fLastSample = (*m_data.pBool) ? 1.0 : 0.0; break; case VT_I1: m_fLastSample = (double)*m_data.pI1; break; case VT_UI1: m_fLastSample = (double)*m_data.pUI1; break; case VT_I2: m_fLastSample = (double)*m_data.pI2; break; case VT_UI2: m_fLastSample = (double)*m_data.pUI2; break; case VT_I4: m_fLastSample = (double)*m_data.pI4; break; case VT_UI4: m_fLastSample = (double)*m_data.pUI4; break; case VT_I8: m_fLastSample = (double)*m_data.pI8; break; case VT_UI8: m_fLastSample = (double)*m_data.pUI8; break; case VT_float: m_fLastSample = (double)*m_data.pFloat; break; case VT_double: m_fLastSample = *m_data.pDouble; break; default: Unlock(); ASSERT(false); return; } if(m_fMin > m_fLastSample) m_fMin = m_fLastSample; if(m_fMax < m_fLastSample) m_fMax = m_fLastSample; m_fSamples += m_fLastSample; m_nSampleCount++; Unlock(); } ///////////////////////////////////////////////////////////////////////////// void CLogVariable::LogInterval(time_t nTimestamp, CDataLogger &rdl) { if(!m_bIsIntervalLog) { m_fSamples = 0; m_nSampleCount = 0; return; } if(!CanLog(true)) { m_fSamples = 0; m_nSampleCount = 0; return; } if(m_nSampleCount > 0) { if(!m_bIsDbPersistant) { if(m_nSampleCount > 1) m_fSamples /= (double)m_nSampleCount; rdl.Log(m_nTagID, m_fSamples, m_fMin, m_fMax, nTimestamp, m_nIndex, m_lt); } else { rdl.Log(m_nTagID, m_fLastSample, m_fMin, m_fMax, nTimestamp, m_nIndex, m_lt); } } m_fSamples = 0; m_fMin = std::numeric_limits::infinity(); m_fMax = -std::numeric_limits::infinity(); m_nSampleCount = 0; } ///////////////////////////////////////////////////////////////////////////// void CLogVariable::LogValueChanged(time_t nTimestamp, CDataLogger &rdl, bool bStartup, bool bWriteNull) { if(m_bIsIntervalLog) return; if(bWriteNull) // force write of a NULL value and exit { rdl.Log(m_nTagID, 0.0, 0.0, 0.0, nTimestamp, m_nIndex, m_lt, true, bStartup); return; } double val; bool bCondition, bConditionChanged, bDoLog = false; bCondition = CanLog(true); bConditionChanged = (m_bOldLogCond != bCondition) || bStartup; m_bOldLogCond = bCondition; if(!bCondition && !bConditionChanged) return; Lock(); switch(m_vt) { case VT_bool: if(bCondition && ((m_cache.boolVal != *m_data.pBool) || bConditionChanged)) // log, if either the value has changed or a condition transition from 0 to 1 has occured { m_cache.boolVal = *m_data.pBool; val = m_cache.boolVal ? 1.0 : 0.0; bDoLog = true; } break; case VT_I1: if(bCondition && ((m_cache.I1Val != *m_data.pI1) || bConditionChanged)) { m_cache.I1Val = *m_data.pI1; val = (double)m_cache.I1Val; bDoLog = true; } break; case VT_UI1: if(bCondition && ((m_cache.UI1Val != *m_data.pUI1) || bConditionChanged)) { m_cache.UI1Val = *m_data.pUI1; val = (double)m_cache.UI1Val; bDoLog = true; } break; case VT_I2: if(bCondition && ((m_cache.I2Val != *m_data.pI2) || bConditionChanged)) { m_cache.I2Val = *m_data.pI2; val = (double)m_cache.I2Val; bDoLog = true; } break; case VT_UI2: if(bCondition && ((m_cache.UI2Val != *m_data.pUI2) || bConditionChanged)) { m_cache.UI2Val = *m_data.pUI2; val = (double)m_cache.UI2Val; bDoLog = true; } break; case VT_I4: if(bCondition && ((m_cache.I4Val != *m_data.pI4) || bConditionChanged)) { m_cache.I4Val = *m_data.pI4; val = (double)m_cache.I4Val; bDoLog = true; } break; case VT_UI4: if(bCondition && ((m_cache.UI4Val != *m_data.pUI4) || bConditionChanged)) { m_cache.UI4Val = *m_data.pUI4; val = (double)m_cache.UI4Val; bDoLog = true; } break; case VT_I8: if(bCondition && ((m_cache.I8Val != *m_data.pI8) || bConditionChanged)) { m_cache.I8Val = *m_data.pI8; val = (double)m_cache.I8Val; bDoLog = true; } break; case VT_UI8: if(bCondition && ((m_cache.UI8Val != *m_data.pUI8) || bConditionChanged)) { m_cache.UI8Val = *m_data.pUI8; val = (double)m_cache.UI8Val; bDoLog = true; } break; case VT_float: if(bCondition && ((m_cache.FloatVal != *m_data.pFloat) || bConditionChanged)) { m_cache.FloatVal = *m_data.pFloat; val = (double)m_cache.FloatVal; bDoLog = true; } break; case VT_double: if(bCondition && ((m_cache.DoubleVal != *m_data.pDouble) || bConditionChanged)) { m_cache.DoubleVal = *m_data.pDouble; val = m_cache.DoubleVal; bDoLog = true; } break; default: ASSERT(false); break; } Unlock(); if(bDoLog) // log value, if either the value has changed or a condition transition from 0 to 1 has occured { rdl.Log(m_nTagID, val, 0.0, 0.0, nTimestamp, m_nIndex, m_lt); } else if(!bCondition && bConditionChanged) // log a NULL value , if a condition transition from 1 to 0 has occured { rdl.Log(m_nTagID, 0.0, 0.0, 0.0, nTimestamp, m_nIndex, m_lt, true); } } ///////////////////////////////////////////////////////////////////////////// void CLogVariable::Lock(void) { ::GfaIpcLockSHM(m_hShm); } ///////////////////////////////////////////////////////////////////////////// void CLogVariable::Unlock(void) { ::GfaIpcUnlockSHM(m_hShm); }