//////////////////////////////////////////////////////////////////////////////// // / // 2012-2020 (c) Baical / // / // This library is free software; you can redistribute it and/or / // modify it under the terms of the GNU Lesser General Public / // License as published by the Free Software Foundation; either / // version 3.0 of the License, or (at your option) any later version. / // / // This library is distributed in the hope that it will be useful, / // but WITHOUT ANY WARRANTY; without even the implied warranty of / // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / // Lesser General Public License for more details. / // / // You should have received a copy of the GNU Lesser General Public / // License along with this library. / // / //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // This file provide telemetry functionality / //////////////////////////////////////////////////////////////////////////////// #include "CommonClient.h" #include "Telemetry.h" #define RESET_UNDEFINED (0xFFFFFFFFUL) #define RESET_FLAG_HEADER (0x1) #define RESET_FLAG_COUNTER (0x2) #define TELEMETRY_SHARED_PREFIX TM("Tel_") #define TELEMETRY_ON_CONNECT_EXIT_SIGNAL (MEVENT_SIGNAL_0) extern "C" { //////////////////////////////////////////////////////////////////////////////// //P7_Create_Telemetry P7_EXPORT IP7_Telemetry * __cdecl P7_Create_Telemetry(IP7_Client *i_pClient, const tXCHAR *i_pName, const stTelemetry_Conf *i_pConf ) { //telemetry isn't supported by next sinks if ( (!i_pClient) || (IP7_Client::eText <= i_pClient->Get_Type()) ) { return NULL; } //Check parameters if (i_pConf) { if ( ( (!i_pConf->qwTimestamp_Frequency) && (i_pConf->pTimestamp_Callback) ) || ( (i_pConf->qwTimestamp_Frequency) && (!i_pConf->pTimestamp_Callback) ) ) { return NULL; } } CP7Telemetry *l_pReturn = new CP7Telemetry(i_pClient, i_pName, i_pConf); //if not initialized - remove if ( (l_pReturn) && (TRUE != l_pReturn->Is_Initialized()) ) { l_pReturn->Release(); l_pReturn = NULL; } return static_cast(l_pReturn); }//P7_Create_Telemetry //////////////////////////////////////////////////////////////////////////////// //P7_Get_Shared_Telemetry P7_EXPORT IP7_Telemetry * __cdecl P7_Get_Shared_Telemetry(const tXCHAR *i_pName) { IP7_Telemetry *l_pReturn = NULL; tUINT32 l_dwLen1 = PStrLen(TELEMETRY_SHARED_PREFIX); tUINT32 l_dwLen2 = PStrLen(i_pName); tXCHAR *l_pName = (tXCHAR *)malloc(sizeof(tXCHAR) * (l_dwLen1 + l_dwLen2 + 16)); tUINT32 l_uTimeHi = 0; tUINT32 l_uTimeLo = 0; sObjShared l_stShared = {}; CShared::hSem l_hSem = SHARED_SEM_NULL; CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo); if (l_pName) { PStrCpy(l_pName, l_dwLen1 + l_dwLen2 + 16, TELEMETRY_SHARED_PREFIX); PStrCpy(l_pName + l_dwLen1, l_dwLen2 + 16, i_pName); if (CShared::E_OK == CShared::Lock(l_pName, l_hSem, 250)) { if (CShared::Read(l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared))) { if ( (l_stShared.uProcTimeHi == l_uTimeHi) && (l_stShared.uProcTimeLo == l_uTimeLo) ) { l_pReturn = static_cast(l_stShared.pPointer); if (l_pReturn) { l_pReturn->Add_Ref(); } } else { CShared::UnLink(l_pName); } } CShared::UnLock(l_hSem); } free(l_pName); l_pName = NULL; } return l_pReturn; }//P7_Get_Shared_Telemetry } //extern "C" //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // CP7Tel_Counter CP7Tel_Counter::CP7Tel_Counter(tUINT16 i_wID, tUINT8 i_bOn, tDOUBLE i_dbMin, tDOUBLE i_dbAlarmMin, tDOUBLE i_dbMax, tDOUBLE i_dbAlarmMax, const tXCHAR *i_pName, tUINT32 i_uHash ) : m_bInitialized(TRUE) , m_pName(PStrDub(i_pName)) , m_bDelivered(FALSE) , m_pHeader(NULL) , m_wSeqN(0) , m_uHash(i_uHash) , pTreeNext(NULL) { size_t l_szCounter = sizeof(sP7Tel_Counter_v2) - P7TELEMETRY_COUNTER_NAME_MIN_LENGTH_V2 * sizeof(tWCHAR); size_t l_szName = PStrLen(i_pName) + 1; l_szCounter += l_szName * sizeof(tWCHAR); m_pHeader = (sP7Tel_Counter_v2*)malloc(l_szCounter); memset(m_pHeader, 0, l_szCounter); INIT_EXT_HEADER(m_pHeader->sCommonRaw, EP7USER_TYPE_TELEMETRY_V2, EP7TEL_TYPE_COUNTER, l_szCounter); //m_sCounter.sCommon.dwSize = sizeof(sP7Tel_Counter); //m_sCounter.sCommon.dwType = EP7USER_TYPE_TELEMETRY; //m_sCounter.sCommon.dwSubType = EP7TEL_TYPE_COUNTER; m_pHeader->wID = i_wID; m_pHeader->bOn = i_bOn; m_pHeader->dbMin = i_dbMin; m_pHeader->dbAlarmMin = i_dbAlarmMin; m_pHeader->dbMax = i_dbMax; m_pHeader->dbAlarmMax = i_dbAlarmMax; PUStrCpy(m_pHeader->pName, (tUINT32)l_szName, i_pName); } // CP7Tel_Counter //////////////////////////////////////////////////////////////////////////////// // ~CP7Tel_Counter CP7Tel_Counter::~CP7Tel_Counter() { if (m_pHeader) { free(m_pHeader); m_pHeader = NULL; } if (m_pName) { PStrFreeDub(m_pName); m_pName = NULL; } }// ~CP7Trace_Item //////////////////////////////////////////////////////////////////////////////// // Get_Hash tUINT32 CP7Tel_Counter::Get_Hash(const tXCHAR *i_pName) { //Here is RedBlackTree keys are calculated //Hash description: http://isthe.com/chongo/tech/comp/fnv/#FNV-param //Hash parameters investigation (collisions, randomnessification) //http://programmers.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed //Collisions: // - Is collisions are possible ? Yes, FNV-1a produce 4 coll. on list of // 216,553 English words. // - If collision happens and even calculated key is not unique - is it // dangerous ? No, in tree we will have additional list (containing // elementS with the same key) where exact item can be found tUINT32 l_uReturn = 2166136261ul; while (*i_pName) { l_uReturn = (l_uReturn ^ (tUINT32)*i_pName) * 16777619ul; i_pName++; } return l_uReturn; } //////////////////////////////////////////////////////////////////////////////// // Has_Name tBOOL CP7Tel_Counter::Has_Name(const tXCHAR *i_pName) { return (0 == PStrCmp(i_pName , m_pName)) ? TRUE : FALSE; }// Has_Name //////////////////////////////////////////////////////////////////////////////// // Is_Initialized tBOOL CP7Tel_Counter::Is_Initialized() { return m_bInitialized; }// Is_Initialized //////////////////////////////////////////////////////////////////////////////// // Enable void CP7Tel_Counter::Enable(tUINT16 i_wOn) { m_pHeader->bOn = i_wOn; }// Enable //////////////////////////////////////////////////////////////////////////////// // CP7Telemetry CP7Telemetry::CP7Telemetry(IP7_Client *i_pClient, const tXCHAR *i_pName, const stTelemetry_Conf *i_pConf) : m_lReference(1) , m_pClient(i_pClient) , m_dwChannel_ID(0) , m_bInitialized(TRUE) , m_bActive(TRUE) , m_pCounters(256) , m_bIsHeaderDelivered(FALSE) , m_pChunks(NULL) , m_dwChunks_Max_Count(64) , m_bIs_Channel(FALSE) , m_hShared(NULL) , m_bOnConnect_Thread(FALSE) , m_hOnConnect_Thread(0) //NULL { if (i_pConf) { m_sConf = *i_pConf; } else { memset(&m_sConf, 0, sizeof(m_sConf)); } memset(&m_sCS, 0, sizeof(m_sCS)); LOCK_CREATE(m_sCS); memset(&m_sHeader_Info, 0, sizeof(m_sHeader_Info)); memset(&m_sHeader_Utc, 0, sizeof(m_sHeader_Utc)); memset(&m_sValue, 0, sizeof(m_sValue)); m_pChunks = new sP7C_Data_Chunk[m_dwChunks_Max_Count]; m_sStatus.bConnected = TRUE; m_sStatus.dwResets = 0; if (NULL == m_pClient) { P7_Set_Last_Error(eP7_Error_NoClient); m_bInitialized = FALSE; } else { m_pClient->Add_Ref(); } if (m_bInitialized) { if (FALSE == m_cOnConnect_Event.Init(1, EMEVENT_SINGLE_MANUAL)) { P7_Set_Last_Error(eP7_Error_OS); m_bInitialized = FALSE; } } if (m_bInitialized) { INIT_EXT_HEADER(m_sHeader_Info.sCommonRaw, EP7USER_TYPE_TELEMETRY_V2, EP7TEL_TYPE_INFO, sizeof(sP7Tel_Info)); //m_sHeader_Info.sCommon.dwSize = sizeof(sP7Trace_Info); //m_sHeader_Info.sCommon.dwType = EP7USER_TYPE_TELEMETRY; //m_sHeader_Info.sCommon.dwSubType = EP7TEL_TYPE_INFO; if (i_pName) { PUStrCpy(m_sHeader_Info.pName, P7TELEMETRY_NAME_LENGTH, i_pName); } else { PUStrCpy(m_sHeader_Info.pName, P7TELEMETRY_NAME_LENGTH, TM("Unknown")); } if (m_sConf.qwTimestamp_Frequency) { m_sHeader_Info.qwTimer_Frequency = m_sConf.qwTimestamp_Frequency; m_sHeader_Info.qwTimer_Value = m_sConf.pTimestamp_Callback(m_sConf.pContext); } else { m_sHeader_Info.qwTimer_Frequency = GetPerformanceFrequency(); m_sHeader_Info.qwTimer_Value = GetPerformanceCounter(); } GetEpochTime(&m_sHeader_Info.dwTime_Hi, &m_sHeader_Info.dwTime_Lo); m_sHeader_Info.qwFlags = P7TELEMETRY_FLAG_TIME_ZONE | P7TELEMETRY_FLAG_EXTENTION; INIT_EXT_HEADER(m_sHeader_Utc.sCommonRaw, EP7USER_TYPE_TELEMETRY_V2, EP7TEL_TYPE_UTC_OFFS, sizeof(sP7Tel_Utc_Offs_V2)); m_sHeader_Utc.iUtcOffsetSec = GetUtcOffsetSeconds(); INIT_EXT_HEADER(m_sValue.sCommonRaw, EP7USER_TYPE_TELEMETRY_V2, EP7TEL_TYPE_VALUE, sizeof(sP7Tel_Value_v2)); //m_sValue.sCommon.dwSize = sizeof(sP7Tel_Value); //m_sValue.sCommon.dwType = EP7USER_TYPE_TELEMETRY; //m_sValue.sCommon.dwSubType = EP7TEL_TYPE_VALUE; } if (m_bInitialized) { m_bIs_Channel = (ECLIENT_STATUS_OK == m_pClient->Register_Channel(this)); m_bInitialized = m_bIs_Channel; if (!m_bInitialized) { P7_Set_Last_Error(eP7_Error_NoFreeChannels); } } m_bActive = m_bInitialized; }// CP7Telemetry //////////////////////////////////////////////////////////////////////////////// // ~CP7Telemetry CP7Telemetry::~CP7Telemetry() { LOCK_ENTER(m_sCS); LOCK_EXIT(m_sCS); if (m_bOnConnect_Thread) { m_cOnConnect_Event.Set(TELEMETRY_ON_CONNECT_EXIT_SIGNAL); CThShell::Close(m_hOnConnect_Thread, 1000); m_hOnConnect_Thread = 0; } if (m_hShared) { CShared::Close(m_hShared); m_hShared = NULL; } if (m_bIs_Channel) { Flush(); m_pClient->Unregister_Channel(m_dwChannel_ID); } m_pCounters.Clear(TRUE); if (m_pClient) { m_pClient->Release(); m_pClient = NULL; } if (m_pChunks) { delete [] m_pChunks; m_pChunks = NULL; } LOCK_DESTROY(m_sCS); }// ~CP7Telemetry //////////////////////////////////////////////////////////////////////////////// // Is_Initialized tBOOL CP7Telemetry::Is_Initialized() { return m_bInitialized; }// Is_Initialized //////////////////////////////////////////////////////////////////////////////// // On_Init void CP7Telemetry::On_Init(sP7C_Channel_Info *i_pInfo) { if (i_pInfo) { m_dwChannel_ID = i_pInfo->dwID; } }// On_Init //////////////////////////////////////////////////////////////////////////////// // On_Receive void CP7Telemetry::On_Receive(tUINT32 i_dwChannel, tUINT8 *i_pBuffer, tUINT32 i_dwSize, tBOOL i_bBigEndian) { UNUSED_ARG(i_dwChannel); UNUSED_ARG(i_bBigEndian); LOCK_ENTER(m_sCS); if ( (i_pBuffer) && (i_dwSize >= sizeof(sP7Ext_Header)) ) { sP7Ext_Raw l_sHeader = *(sP7Ext_Raw*)i_pBuffer; if (EP7USER_TYPE_TELEMETRY_V2 == GET_EXT_HEADER_TYPE(l_sHeader)) { if (EP7TEL_TYPE_ENABLE == GET_EXT_HEADER_SUBTYPE(l_sHeader)) { sP7Tel_Enable_v2 *l_pEnable = (sP7Tel_Enable_v2*)i_pBuffer; if (m_pCounters[l_pEnable->wID]) { m_pCounters[l_pEnable->wID]->Enable(l_pEnable->bOn); if (m_sConf.pEnable_Callback) { m_sConf.pEnable_Callback(m_sConf.pContext, l_pEnable->wID, l_pEnable->bOn); } } } else if (EP7TEL_TYPE_DELETE == GET_EXT_HEADER_SUBTYPE(l_sHeader)) { Flush(); m_bActive = FALSE; } } } LOCK_EXIT(m_sCS); }// On_Receive //////////////////////////////////////////////////////////////////////////////// // On_Status void CP7Telemetry::On_Status(tUINT32 i_dwChannel, const sP7C_Status *i_pStatus) { UNUSED_ARG(i_dwChannel); LOCK_ENTER(m_sCS); if (i_pStatus) { m_sStatus = *i_pStatus; if (m_sConf.pConnect_Callback) { m_sConf.pConnect_Callback(m_sConf.pContext, m_sStatus.bConnected); } //if connection was established - sent counters description if (m_sStatus.bConnected) { if (m_bOnConnect_Thread) { m_cOnConnect_Event.Set(TELEMETRY_ON_CONNECT_EXIT_SIGNAL); CThShell::Close(m_hOnConnect_Thread, 1000); m_hOnConnect_Thread = 0; m_bOnConnect_Thread = FALSE; } m_bIsHeaderDelivered = FALSE; pAList_Cell l_pEl = NULL; while ((l_pEl = m_pCounters.Get_Next(l_pEl))) { CP7Tel_Counter *l_pCounter = m_pCounters.Get_Data(l_pEl); if (l_pCounter) { l_pCounter->m_bDelivered = FALSE; } } m_cOnConnect_Event.Clr(TELEMETRY_ON_CONNECT_EXIT_SIGNAL); if (CThShell::Create(&Static_OnConnect_Routine, this, &m_hOnConnect_Thread, TM("P7:Tel:OnConnect") ) ) { m_bOnConnect_Thread = TRUE; } } else { m_bIsHeaderDelivered = FALSE; if (m_bOnConnect_Thread) { m_cOnConnect_Event.Set(TELEMETRY_ON_CONNECT_EXIT_SIGNAL); CThShell::Close(m_hOnConnect_Thread, 1000); m_hOnConnect_Thread = 0; m_bOnConnect_Thread = FALSE; } m_cOnConnect_Event.Clr(TELEMETRY_ON_CONNECT_EXIT_SIGNAL); pAList_Cell l_pEl = NULL; while ((l_pEl = m_pCounters.Get_Next(l_pEl))) { CP7Tel_Counter *l_pCounter = m_pCounters.Get_Data(l_pEl); if (l_pCounter) { l_pCounter->m_bDelivered = FALSE; } } } } LOCK_EXIT(m_sCS); }// On_Status //////////////////////////////////////////////////////////////////////////////// // On_Flush - external call void CP7Telemetry::On_Flush(tUINT32 i_dwChannel, tBOOL *io_pCrash) { UNUSED_ARG(i_dwChannel); LOCK_ENTER(m_sCS); if ( (io_pCrash) && (TRUE == *io_pCrash) && (m_bActive) ) { //nothing special for crash event } Flush(); LOCK_EXIT(m_sCS); }// On_Flush //////////////////////////////////////////////////////////////////////////////// // Create, i_pName is case sensitive and should be unique tBOOL CP7Telemetry::Create(const tXCHAR *i_pName, tDOUBLE i_dbMin, tDOUBLE i_dbAlarmMin, tDOUBLE i_dbMax, tDOUBLE i_dbAlarmMax, tBOOL i_bOn, tUINT16 *o_pID ) { tBOOL l_bReturn = FALSE; sCounterMap *l_pMap = NULL; tUINT32 l_uiId = 0; CP7Tel_Counter *l_pCounter = NULL; tUINT32 l_uHash = 0; if ( (FALSE == m_bActive) || (NULL == i_pName) || (NULL == o_pID) ) { return FALSE; } LOCK_ENTER(m_sCS); *o_pID = P7TELEMETRY_INVALID_ID_V2; l_uHash = CP7Tel_Counter::Get_Hash(i_pName); //////////////////////////////////////////////////////////////////////////// //find by name already existing counter l_pMap = m_cCounters_Map.Find(l_uHash); if (l_pMap) { l_pCounter = l_pMap->pCounter; while (l_pCounter) { if (l_pCounter->Has_Name(i_pName)) { //found, and all parameters are the same ... if ( (l_pCounter->m_pHeader->dbMin == i_dbMin) && (l_pCounter->m_pHeader->dbMax == i_dbMax) && (l_pCounter->m_pHeader->dbAlarmMin == i_dbAlarmMin) && (l_pCounter->m_pHeader->dbAlarmMax == i_dbAlarmMax) ) { *o_pID = l_pCounter->m_pHeader->wID; l_bReturn = TRUE; goto l_lblExit; } else //name is equal, but some additional parameters are different { goto l_lblExit; } } l_pCounter = l_pCounter->pTreeNext; } } l_pCounter = NULL; if (P7TELEMETRY_INVALID_ID_V2 <= m_pCounters.Count()) { goto l_lblExit; } l_uiId = m_pCounters.Count(); l_pCounter = new CP7Tel_Counter((tUINT16)l_uiId, i_bOn, i_dbMin, i_dbAlarmMin, i_dbMax, i_dbAlarmMax, i_pName, l_uHash ); if ( (NULL == l_pCounter) || (FALSE == l_pCounter->Is_Initialized()) ) { if (l_pCounter) { delete l_pCounter; l_pCounter = NULL; } goto l_lblExit; } if (l_pMap) { l_pCounter->pTreeNext = l_pMap->pCounter; l_pMap->pCounter = l_pCounter; } else { m_cCounters_Map.Push(new sCounterMap(l_pCounter), l_uHash); } if (m_sStatus.bConnected) { sP7C_Data_Chunk *l_pChunk = m_pChunks; tBOOL l_bHeader = FALSE; tUINT32 l_dwSize = 0; //connection was lost, we need to resend initial data if (!m_bIsHeaderDelivered) { l_bHeader = TRUE; l_pChunk->dwSize = sizeof(m_sHeader_Info); l_pChunk->pData = &m_sHeader_Info; l_dwSize += l_pChunk->dwSize; l_pChunk ++; l_pChunk->dwSize = sizeof(m_sHeader_Utc); l_pChunk->pData = &m_sHeader_Utc; l_dwSize += l_pChunk->dwSize; l_pChunk ++; } l_pChunk->pData = l_pCounter->m_pHeader; l_pChunk->dwSize = GET_EXT_HEADER_SIZE(l_pCounter->m_pHeader->sCommonRaw);//m_pCounters[m_dwUsed]->m_sCounter.sCommon.dwSize; l_dwSize += l_pChunk->dwSize; l_pChunk ++; if (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, m_pChunks, (tUINT32)(l_pChunk - m_pChunks), l_dwSize)) { l_pCounter->m_bDelivered = TRUE; if (l_bHeader) { m_bIsHeaderDelivered = TRUE; } } } l_bReturn = TRUE; *o_pID = (tUINT16)l_uiId; m_pCounters.Add_After(m_pCounters.Get_Last(), l_pCounter); l_lblExit: LOCK_EXIT(m_sCS); return l_bReturn; } //Create //////////////////////////////////////////////////////////////////////////////// // Find, i_pName is case sensitive tBOOL CP7Telemetry::Find(const tXCHAR *i_pName, tUINT16 *o_pID) { sCounterMap *l_pMap = NULL; tBOOL l_bReturn = FALSE; if (o_pID) { *o_pID = P7TELEMETRY_INVALID_ID_V2; } else { return FALSE; } if ( (FALSE == m_bActive) || (NULL == i_pName) ) { return FALSE; } LOCK_ENTER(m_sCS); l_pMap = m_cCounters_Map.Find(CP7Tel_Counter::Get_Hash(i_pName)); if (l_pMap) { CP7Tel_Counter *l_pCounter = l_pMap->pCounter; while (l_pCounter) { if (l_pCounter->Has_Name(i_pName)) { *o_pID = l_pCounter->m_pHeader->wID; l_bReturn = TRUE; break; } l_pCounter = l_pCounter->pTreeNext; } } LOCK_EXIT(m_sCS); return l_bReturn; }// Find //////////////////////////////////////////////////////////////////////////////// // Add tBOOL CP7Telemetry::Add(tUINT16 i_bID, tDOUBLE i_dbValue) { tBOOL l_bReturn = TRUE; tUINT32 l_dwSize = 0; tUINT8 l_bReset = 0; CP7Tel_Counter *l_pCounter; //will be initialized lated sP7C_Data_Chunk *l_pChunk; //will be initialized lated if (P7TELEMETRY_INVALID_ID_V2 == i_bID) { return FALSE; } LOCK_ENTER(m_sCS); l_pCounter = m_pCounters[i_bID]; //////////////////////////////////////////////////////////////////////////// //check ID if ( (NULL == l_pCounter) || (FALSE == m_bActive) || (FALSE == m_sStatus.bConnected) || (!l_pCounter->m_pHeader->bOn) ) { l_bReturn = FALSE; goto l_lblExit; } l_pChunk = m_pChunks; //connection was lost, we need to resend initial data if (!m_bIsHeaderDelivered) { l_bReset |= RESET_FLAG_HEADER; l_pChunk->dwSize = sizeof(m_sHeader_Info); l_pChunk->pData = &m_sHeader_Info; l_dwSize += l_pChunk->dwSize; l_pChunk ++; l_pChunk->dwSize = sizeof(m_sHeader_Utc); l_pChunk->pData = &m_sHeader_Utc; l_dwSize += l_pChunk->dwSize; l_pChunk ++; } //counters descriptions have to send again if (!l_pCounter->m_bDelivered) { l_bReset |= RESET_FLAG_COUNTER; l_pChunk->pData = l_pCounter->m_pHeader; l_pChunk->dwSize = GET_EXT_HEADER_SIZE(l_pCounter->m_pHeader->sCommonRaw);//(*l_pIter)->m_sCounter.sCommon.dwSize; l_dwSize += l_pChunk->dwSize; l_pChunk ++; } m_sValue.wID = i_bID; m_sValue.dbValue = i_dbValue; m_sValue.wSeqN = l_pCounter->m_wSeqN ++; if (! m_sConf.pTimestamp_Callback ) { m_sValue.qwTimer = GetPerformanceCounter(); } else { m_sValue.qwTimer = m_sConf.pTimestamp_Callback(m_sConf.pContext); } l_pChunk->pData = &m_sValue; l_pChunk->dwSize = GET_EXT_HEADER_SIZE(m_sValue.sCommonRaw);//m_sValue.sCommon.dwSize; l_dwSize += l_pChunk->dwSize; l_pChunk ++; if (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, m_pChunks, (tUINT32)(l_pChunk - m_pChunks), l_dwSize ) ) { if (l_bReset & RESET_FLAG_HEADER) { m_bIsHeaderDelivered = TRUE; } if (l_bReset & RESET_FLAG_COUNTER) { l_pCounter->m_bDelivered = TRUE; } } else { l_bReturn = FALSE; } l_lblExit: LOCK_EXIT(m_sCS); return l_bReturn; }// Add //////////////////////////////////////////////////////////////////////////////// // Set_Enable tBOOL CP7Telemetry::Set_Enable(tUINT16 i_wID, tBOOL i_bEnable) { tBOOL l_bReturn = FALSE; if (!m_bInitialized) { return l_bReturn; } LOCK_ENTER(m_sCS); if (m_bActive) { CP7Tel_Counter *l_pCounter = m_pCounters[i_wID]; if (l_pCounter) { l_bReturn = TRUE; l_pCounter->m_pHeader->bOn = (tUINT16)i_bEnable; } } LOCK_EXIT(m_sCS); return l_bReturn; } //////////////////////////////////////////////////////////////////////////////// // Get_Enable tBOOL CP7Telemetry::Get_Enable(tUINT16 i_wID) { tBOOL l_bReturn = FALSE; if (!m_bInitialized) { return l_bReturn; } LOCK_ENTER(m_sCS); CP7Tel_Counter *l_pCounter = m_pCounters[i_wID]; if (l_pCounter) { l_bReturn = (tBOOL)l_pCounter->m_pHeader->bOn; } LOCK_EXIT(m_sCS); return l_bReturn; } //////////////////////////////////////////////////////////////////////////////// // Get_Min tDOUBLE CP7Telemetry::Get_Min(tUINT16 i_wID) { tDOUBLE l_dbReturn = 0.0; if (!m_bInitialized) { return l_dbReturn; } LOCK_ENTER(m_sCS); CP7Tel_Counter *l_pCounter = m_pCounters[i_wID]; if (l_pCounter) { l_dbReturn = l_pCounter->m_pHeader->dbMin; } LOCK_EXIT(m_sCS); return l_dbReturn; } //////////////////////////////////////////////////////////////////////////////// // Get_Max tDOUBLE CP7Telemetry::Get_Max(tUINT16 i_wID) { tDOUBLE l_dbReturn = 0.0; if (!m_bInitialized) { return l_dbReturn; } LOCK_ENTER(m_sCS); CP7Tel_Counter *l_pCounter = m_pCounters[i_wID]; if (l_pCounter) { l_dbReturn = l_pCounter->m_pHeader->dbMax; } LOCK_EXIT(m_sCS); return l_dbReturn; } //////////////////////////////////////////////////////////////////////////////// // Get_Name const tXCHAR *CP7Telemetry::Get_Name(tUINT16 i_wID) { const tXCHAR *l_pReturn = NULL; if (!m_bInitialized) { return l_pReturn; } LOCK_ENTER(m_sCS); CP7Tel_Counter *l_pCounter = m_pCounters[i_wID]; if (l_pCounter) { l_pReturn = l_pCounter->m_pName; } LOCK_EXIT(m_sCS); return l_pReturn; } //////////////////////////////////////////////////////////////////////////////// // Get_Count tUINT16 CP7Telemetry::Get_Count() { tUINT16 l_wReturn = 0; if (!m_bInitialized) { return l_wReturn; } LOCK_ENTER(m_sCS); l_wReturn = m_pCounters.Count(); LOCK_EXIT(m_sCS); return l_wReturn; } //////////////////////////////////////////////////////////////////////////////// // Share tBOOL CP7Telemetry::Share(const tXCHAR *i_pName) { tBOOL l_bReturn = FALSE; LOCK_ENTER(m_sCS); if (NULL == m_hShared) { tUINT32 l_dwLen1 = PStrLen(TELEMETRY_SHARED_PREFIX); tUINT32 l_dwLen2 = PStrLen(i_pName); tXCHAR *l_pName = (tXCHAR *)malloc(sizeof(tXCHAR) * (l_dwLen1 + l_dwLen2 + 16)); CShared::hSem l_hSem = SHARED_SEM_NULL; if (l_pName) { sObjShared l_stShared = {}; tUINT32 l_uTimeHi = 0; tUINT32 l_uTimeLo = 0; tBOOL l_bCreate = TRUE; CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo); PStrCpy(l_pName, l_dwLen1 + l_dwLen2 + 16, TELEMETRY_SHARED_PREFIX); PStrCpy(l_pName + l_dwLen1, l_dwLen2 + 16, i_pName); //JOURNAL_WARNING(m_pLog, TM("Shared memory {%s} registration error"), l_pName); if (CShared::E_OK == CShared::Lock(l_pName, l_hSem, 250)) { l_bCreate = FALSE; //it is already existing if (CShared::Read(l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared))) { if ( (l_stShared.uProcTimeHi != l_uTimeHi) || (l_stShared.uProcTimeLo != l_uTimeLo) ) { //JOURNAL_ERROR(m_pLog, TM("Shared memory timestamp error, prev. session crashed or forget to release P7 objects?")); CShared::UnLink(l_pName); l_bCreate = TRUE; } } CShared::UnLock(l_hSem); } if (l_bCreate) { CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo); l_stShared.pPointer = static_cast(this); l_stShared.uProcTimeHi = l_uTimeHi; l_stShared.uProcTimeLo = l_uTimeLo; l_bReturn = CShared::Create(&m_hShared, l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared)); } free(l_pName); l_pName = NULL; } } LOCK_EXIT(m_sCS); return l_bReturn; }// Share //////////////////////////////////////////////////////////////////////////////// // On_Flush - internal call void CP7Telemetry::Flush() { if (FALSE == m_bActive) { return; } m_bActive = FALSE; //inform server about channel closing, I didn't check status, just //sending data if (m_bIsHeaderDelivered) { sP7Ext_Raw l_sHeader; INIT_EXT_HEADER(l_sHeader, EP7USER_TYPE_TELEMETRY_V2, EP7TEL_TYPE_CLOSE, sizeof(sP7Ext_Raw)); sP7C_Data_Chunk l_sChunk = {&l_sHeader, sizeof(sP7Ext_Raw)}; m_pClient->Sent(m_dwChannel_ID, &l_sChunk, 1, l_sChunk.dwSize); } }// On_Flush //////////////////////////////////////////////////////////////////////////////// // OnConnect_Routine void CP7Telemetry::OnConnect_Routine() { tUINT32 l_uTimeOut = 0; pAList_Cell l_pCounterEl = NULL; tBOOL l_bExit = FALSE; CP7Tel_Counter * l_pCounter = NULL; sP7C_Data_Chunk l_stChunk; while (FALSE == l_bExit) { if (TELEMETRY_ON_CONNECT_EXIT_SIGNAL == m_cOnConnect_Event.Wait(l_uTimeOut)) { break; } if (LOCK_TRY(m_sCS)) { if (!m_bIsHeaderDelivered) { sP7C_Data_Chunk l_stChunk[2]; l_stChunk[0].dwSize = sizeof(m_sHeader_Info); l_stChunk[0].pData = &m_sHeader_Info; l_stChunk[1].dwSize = sizeof(m_sHeader_Utc); l_stChunk[1].pData = &m_sHeader_Utc; if (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, l_stChunk, LENGTH(l_stChunk), l_stChunk[0].dwSize + l_stChunk[1].dwSize ) ) { m_bIsHeaderDelivered = TRUE; } } if (m_bIsHeaderDelivered) { tBOOL l_bDelivering = TRUE; if (!l_pCounterEl) { l_pCounterEl = m_pCounters.Get_First(); } while ( (l_pCounterEl) && (l_bDelivering) ) { l_pCounter = m_pCounters.Get_Data(l_pCounterEl); if (l_pCounter) { if (!l_pCounter->m_bDelivered) { l_stChunk.pData = l_pCounter->m_pHeader; l_stChunk.dwSize = GET_EXT_HEADER_SIZE(l_pCounter->m_pHeader->sCommonRaw); if (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, &l_stChunk, 1, l_stChunk.dwSize)) { l_pCounter->m_bDelivered = TRUE; l_pCounterEl = m_pCounters.Get_Next(l_pCounterEl); l_uTimeOut = 0; } else { l_uTimeOut = 5; l_bDelivering = FALSE; } } else { l_pCounterEl = m_pCounters.Get_Next(l_pCounterEl); } } } if (!l_pCounterEl) { l_bExit = TRUE; } } LOCK_EXIT(m_sCS); } } m_cOnConnect_Event.Clr(TELEMETRY_ON_CONNECT_EXIT_SIGNAL); }