- Naming style migrated to camel-case - P7lib logger sources added - Vcpkg manifest, CMake presets and build moved to root - SDL2, Vulkan and RmlUi dependencies added - Logger LOG macro added - Logger configuration - SDL2 window configuration - Vulkan configuration - RmlUi configuration - SDL event loop
1182 lines
35 KiB
C++
1182 lines
35 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
// /
|
|
// 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<IP7_Telemetry *>(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<IP7_Telemetry *>(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<IP7_Telemetry*>(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);
|
|
}
|
|
|
|
|