/*
 * Copyright (c) 2013, Linz Center of Mechatronics GmbH (LCM), web: www.lcm.at
 * All rights reserved.
 */
/*
 * This file is licensed according to the BSD 3-clause license as follows:
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the "Linz Center of Mechatronics GmbH" and "LCM" nor
 *       the names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL "Linz Center of Mechatronics GmbH" BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * This file is part of X2C. web: x2c.lcm.at
 * $LastChangedRevision: 4343 $
 * $LastChangedDate:: 2026-07-08 18:19:38 +0200#$
 */
#include <stdbool.h>
#include <stddef.h>
#include "CommonFcts.h"
#include "TableStruct.h"
#include "Scope_Main.h"

/* Private prototypes */
static bool isTriggerEvent(SCOPE_MAIN *pTScope, uint64 curTrgValue);
static uint64 getTriggerValue(SCOPE_MAIN *pTScope);
static void sampleData(SCOPE_MAIN *pTScope);

ALIGNTYPE ScopeArray[SCOPE_SIZE];

/**
 * Scope version.
 */
#define SCOPE_VERSION (3U)

#define SOURCE_TYPE_ADDRESS      (0U)
#define SOURCE_TYPE_CONTROLBLOCK (1U)
#define SOURCE_TYPE_INPORTBLOCK  (2U)
#define SOURCE_TYPE_OUTPORTBLOCK (3U)

#define TRG_MODE_AUTO   (0U)
#define TRG_MODE_NORMAL (1U)

/************************************************/
/*  Scope_Main_Init                             */
/************************************************/
void Scope_Main_Init(SCOPE_MAIN *pTScope)
{
	uint8 i;

	pTScope->ID = SCOPE_MAIN_ID;
	for (i=0; i<MAX_SCOPE_CHANNELS; i++)
	{
		pTScope->channelAddr[i] = NULL;
		pTScope->dataSize[i] = 0U;
	}

	pTScope->arrayAddr = (void*)ScopeArray;
	pTScope->trgLevel = 0U;
	pTScope->trgLastValue = 0U;
	pTScope->trgAddr = NULL;
	pTScope->trgDataType = 0U;
	pTScope->state = SCOPE_IDLE;
	pTScope->offlinePtr = 0U;
	pTScope->dataSizeTotal = 0U;
	pTScope->noChannels = 0U;
	pTScope->stf = 0U;
    pTScope->stfCnt = 0U;
	pTScope->timestamp = 0U;
    pTScope->txFrameSize = 0U;
	pTScope->trgDelay = 0;
	pTScope->trgEventPos = 0;
	pTScope->trgCountReached = 0U;
	pTScope->trgCount = 0U;
	pTScope->maxUsedLength = SCOPE_SIZE;
	pTScope->trgEdge = EDGE_RISING;
	pTScope->arraySize = SCOPE_SIZE;

	TableStruct->piScope = pTScope;
}



/************************************************/
/*  Scope_Main_Update                           */
/************************************************/
void Scope_Main_Update(SCOPE_MAIN *pTScope)
{
	uint64 curTrgValue;

	switch (pTScope->state)
	{
		case SCOPE_IDLE:
			break;
		case SCOPE_SAMPLE_ONLINE:
			pTScope->timestamp++;
            pTScope->stfCnt++;
            break;
        case SCOPE_SAMPLE_OFFLINE:
            /* Check if sample time prescaler is reached */
            if (pTScope->stfCnt >= pTScope->stf)
            {
                pTScope->stfCnt = 0U;

				sampleData(pTScope);

                /* if size of next data size would exceed SCOPE_SIZE, the */
                /* offline sampling mode will be stopped (change to idle state) */
                if ((pTScope->offlinePtr + pTScope->dataSizeTotal) > SCOPE_SIZE)
                {
                    pTScope->state = SCOPE_IDLE;
                }
            }
            else
            {
                pTScope->stfCnt++;
            }
            pTScope->timestamp++;
            break;
        /* wait for trigger in online mode */
        case SCOPE_WAITTRGPOS_ONLINE:
        case SCOPE_WAITTRGNEG_ONLINE:
        	curTrgValue = getTriggerValue(pTScope);
        	if (isTriggerEvent(pTScope, curTrgValue))
        	{
        		pTScope->state = SCOPE_SAMPLE_ONLINE;
        	}
        	else
        	{
        		pTScope->trgLastValue = curTrgValue;
        	}
            break;

        /* wait for trigger in offline mode */
		case SCOPE_WAITTRG_OFFLINE:
			if (pTScope->stfCnt >= pTScope->stf)
			{
				pTScope->stfCnt = 0U;
				/* reset array ptr if next dataset would exceed scope buffer size */
				if ((pTScope->offlinePtr + pTScope->dataSizeTotal) > SCOPE_SIZE)
				{
					pTScope->offlinePtr = 0U;
				}

				sampleData(pTScope);

				/* checks for minimum samples (= trigger delay) */
				if (pTScope->offlinePtr >= pTScope->trgCount)
				{
					pTScope->trgCountReached = 1U;
				}
			}
			else
			{
			    pTScope->stfCnt++;
			}

			curTrgValue = getTriggerValue(pTScope);
			if (isTriggerEvent(pTScope, curTrgValue) && pTScope->trgCountReached)
			{
				if (pTScope->trgDelay < 0)
				{
					pTScope->trgEventPos = pTScope->trgDelay;
					pTScope->offlinePtr = 0U;
					pTScope->state = SCOPE_WAIT_TRG_NEG_DELAY;
				}
				else
				{
					if (pTScope->offlinePtr > 0U)
					{
						/**
						 * In case of STF > 0:
						 * Trigger event position = current offline pointer because next sample is
						 * the first 'after trigger' sample.
						 * In case of STF == 0:
						 * Current sample is first 'after trigger' sample, so the 'trigger event sample'
						 * was the previous sample.
						 */
						if (pTScope->stfCnt != 0U)
						{
							pTScope->trgEventPos = pTScope->offlinePtr;
						}
						else
						{
							pTScope->trgEventPos = pTScope->offlinePtr - pTScope->dataSizeTotal;
						}
					}
					else
					{
						pTScope->trgEventPos = pTScope->maxUsedLength - pTScope->dataSizeTotal;
					}
					pTScope->state = SCOPE_TRG_SAMPLE_OFFLINE;
				}
			}
			else
			{
				pTScope->trgLastValue = curTrgValue;
			}
			break;

		case SCOPE_WAIT_TRG_NEG_DELAY:
			/* in case of negative delay wait until delay time has been passed */
			if (pTScope->stfCnt >= pTScope->stf)
			{
				pTScope->stfCnt = 0U;

				pTScope->trgEventPos += pTScope->dataSizeTotal;
				if (pTScope->trgEventPos >= 0)
				{
					pTScope->state = SCOPE_SAMPLE_OFFLINE;
				}
			}
			else
			{
			    pTScope->stfCnt++;
			}
			break;

		case SCOPE_TRG_SAMPLE_OFFLINE:
            if (pTScope->stfCnt >= pTScope->stf)
            {
                pTScope->stfCnt = 0U;

				if ((pTScope->offlinePtr + pTScope->dataSizeTotal) > SCOPE_SIZE)
				{
					pTScope->offlinePtr = 0U;
				}

				sampleData(pTScope);

				if (((pTScope->trgEventPos - pTScope->offlinePtr) <= pTScope->trgDelay) ||
					((pTScope->trgEventPos - pTScope->offlinePtr + pTScope->maxUsedLength) <= pTScope->trgDelay))
				{
					pTScope->state = SCOPE_IDLE;
				}

			}
            else
            {
                pTScope->stfCnt++;
            }
			break;
		default:
            /* Invalid state -> Reset to IDLE state */
            pTScope->state = SCOPE_IDLE;
            break;
	}
}

/************************************************/
/*  Scope_Main_Load                             */
/************************************************/
uint8 Scope_Main_Load(const SCOPE_MAIN *pTScope, uint8 data[], uint16 *dataLength, uint16 maxSize)
{
	uint8 error = 0U;
	if (maxSize < 29U)
	{
		error = 1U;
	}
	else
	{
		data[0] = (uint8)pTScope->state;
		data[1] = pTScope->noChannels;
		data[2] = (uint8)(pTScope->stf & 0xFFU);
		data[3] = (uint8)((pTScope->stf >> 8) & 0xFFU);
		data[4] = (uint8)(pTScope->offlinePtr & 0xFFU);
		data[5] = (uint8)((pTScope->offlinePtr >> 8) & 0xFFU);
		data[6] = (uint8)((pTScope->offlinePtr >> 16) & 0xFFU);
		data[7] = (uint8)((pTScope->offlinePtr >> 24) & 0xFFU);
		data[8] = (uint8)((uint32)pTScope->arrayAddr & 0xFFU);
		data[9] = (uint8)(((uint32)pTScope->arrayAddr >> 8) & 0xFFU);
		data[10] = (uint8)(((uint32)pTScope->arrayAddr >> 16) & 0xFFU);
		data[11] = (uint8)(((uint32)pTScope->arrayAddr >> 24) & 0xFFU);

		data[12] = (uint8)((uint32)pTScope->trgDelay & 0xFFU);
		data[13] = (uint8)(((uint32)pTScope->trgDelay >> 8) & 0xFFU);
		data[14] = (uint8)(((uint32)pTScope->trgDelay >> 16) & 0xFFU);
		data[15] = (uint8)(((uint32)pTScope->trgDelay >> 24) & 0xFFU);
		data[16] = (uint8)((uint32)pTScope->trgEventPos & 0xFFU);
		data[17] = (uint8)(((uint32)pTScope->trgEventPos >> 8) & 0xFFU);
		data[18] = (uint8)(((uint32)pTScope->trgEventPos >> 16) & 0xFFU);
		data[19] = (uint8)(((uint32)pTScope->trgEventPos >> 24) & 0xFFU);

		data[20] = (uint8)(pTScope->maxUsedLength & 0xFFU);
		data[21] = (uint8)((pTScope->maxUsedLength >> 8) & 0xFFU);
		data[22] = (uint8)((pTScope->maxUsedLength >> 16) & 0xFFU);
		data[23] = (uint8)((pTScope->maxUsedLength >> 24) & 0xFFU);

		data[24] = (uint8)(pTScope->arraySize & 0xFFU);
		data[25] = (uint8)((pTScope->arraySize >> 8) & 0xFFU);
		data[26] = (uint8)((pTScope->arraySize >> 16) & 0xFFU);
		data[27] = (uint8)((pTScope->arraySize >> 24) & 0xFFU);

		data[28] = 0x80U | SCOPE_VERSION;

		*dataLength = 29U;
	}

	return (error);
}

/************************************************/
/*  Scope_Main_Save                             */
/************************************************/
uint8 Scope_Main_Save(SCOPE_MAIN *pTScope, const uint8 data[], uint16 dataLength)
{
   const uint16 offset = 4U;
   uint8 i = 0U;
   uint16 ptr = offset;
   uint8 sourceType;

   if (dataLength < offset)
   {
       return (1U);
   }
   else if (data[1] > MAX_SCOPE_CHANNELS)
   {
       /* Send error if selected channels > max channels */
       return (1U);
   }
   else if (data[1] == 0U)
   {
       /* Send error if no channels are configured */
       return (1U);
   }
   else
   {
	   /* IMPORTANT - DO NOT MOVE THIS SETION TO OTHER PARTS */
	   /* OF THE SAVE FUNCTION */
	   /* set state to idle & number of inputs to 0 to avoid */
	   /* undefined behaviour while updating the addresses */
	   /* & scope values if Scope Update function is */
	   /* executed in sample time irq */
	   pTScope->state = SCOPE_IDLE;
	   pTScope->noChannels = 0U;

       /* Scope Save Frame contains the following parameters: */
       /* - Scope State (1 byte) */
       /* - Number of Inputs (1 byte) */
       /* - Sample Time Prescaler (2 bytes) */
	   /* - Channel #1 Source type (1 byte) */
       /* - Channel #1 Address (4 bytes) */
       /* - Channel #1 DataType (1 byte) */
       /* - ... */
	   /* - Channel #n Source type (1 byte) */
       /* - Channel #n Address (2 bytes) */
       /* - Channel #n DataType (1 byte) */
       /* - Trigger DataType (1 byte) */
	   /* - Trigger Source type (1 byte) */
       /* - Trigger Address (4 bytes) */
       /* - Trigger Level (length depends on trigger level size) */
	   /* - Trigger Delay (4 bytes) */
	   /* - Trigger Edge (1 byte) */
	   /* - Trigger mode (1 byte) */
       pTScope->timestamp = 0U;
       pTScope->offlinePtr = 0U;
       pTScope->stf = (uint16)data[2] | ((uint16)data[3] << 8);
       pTScope->stfCnt = pTScope->stf;
       pTScope->trgLastValue = 0U;

       pTScope->dataSizeTotal = 0U;
       /* 2 bytes for 16 bit timestamp */
       pTScope->txFrameSize = 2U;

	   pTScope->trgCountReached = 0U;
	   pTScope->trgEventPos = 0;

       while (i < data[1])
       {
    	   sourceType = data[ptr];
    	   ptr++;

    	   switch (sourceType)
    	   {
			   case SOURCE_TYPE_CONTROLBLOCK:
			   {
				   void* blockAddr;
				   uint16 tblIndex, blockId;
				   uint16 elementId = (uint16)data[ptr] | ((uint16)data[ptr + 1U] << 8);
				   uint16 paramId = (uint16)data[ptr + 2U] | ((uint16)data[ptr + 3U] << 8);
				   uint8 error = getBlockParamIndex(TableStruct->TParamTable, paramId, &tblIndex);
				   if (error != ERROR_SUCCESS)
				   {
					   return (1U);
				   }
				   blockAddr = TableStruct->TParamTable[tblIndex].pAdr;

				   blockId = *(uint16*)blockAddr;
				   error = getBlockFunctionIndex(TableStruct->TFncTable, blockId, &tblIndex);
				   if (error != ERROR_SUCCESS)
				   {
					   return (1U);
				   }
				   pTScope->channelAddr[i] = TableStruct->TFncTable[tblIndex].pFGetAddress(blockAddr, elementId);
				   if (pTScope->channelAddr[i] == NULL)
				   {
					   return (1U);
				   }
				   break;
			   }
			   case SOURCE_TYPE_INPORTBLOCK:
			   {
				   uint16 tblIndex;
				   uint16 paramId = (uint16)data[ptr + 2U] | ((uint16)data[ptr + 3U] << 8);
				   uint8 error = getIoParamIndex(TableStruct->inportParamTable, paramId, &tblIndex);
				   if (error != ERROR_SUCCESS)
				   {
					   return (1U);
				   }
				   pTScope->channelAddr[i] = TableStruct->inportParamTable[tblIndex].data;
				   break;
			   }
			   case SOURCE_TYPE_OUTPORTBLOCK:
			   {
				   uint16 tblIndex;
				   uint16 paramId = (uint16)data[ptr + 2U] | ((uint16)data[ptr + 3U] << 8);
				   uint8 error = getIoParamIndex(TableStruct->outportParamTable, paramId, &tblIndex);
				   if (error != ERROR_SUCCESS)
				   {
					   return (1U);
				   }
				   pTScope->channelAddr[i] = *(void**)TableStruct->outportParamTable[tblIndex].data;
				   break;
			   }
			   case SOURCE_TYPE_ADDRESS:
				   pTScope->channelAddr[i] = (void*)((uint32)data[ptr] | ((uint32)data[ptr + 1U] << 8) |
						   ((uint32)data[ptr + 2U] << 16) | ((uint32)data[ptr + 3U] << 24));
				   break;
			   default:
			       /* Unsupported source type */
			       return (1U);
    	   }

          pTScope->dataSize[i] = data[ptr + 4U];

          pTScope->dataSizeTotal += pTScope->dataSize[i];
#if defined(__DATA_WIDTH_16BIT__)
          pTScope->txFrameSize += (pTScope->dataSize[i]*2);
#elif defined(__DATA_WIDTH_8BIT__)
          pTScope->txFrameSize += (pTScope->dataSize[i]);
#else
#error DATA WIDTH NOT DEFINED
#endif

          pTScope->maxUsedLength = SCOPE_SIZE - (SCOPE_SIZE % pTScope->dataSizeTotal);

          ptr += 5U;
          i++;
       }

       /* trigger parameters */

       /**
        * Trigger data type:
        * 0b 1000 0000
        *         ++++--- Data type byte size
        *       + ------- reserved
        *      +- ------- Signed (1) / Unsigned (0)
        *     +-- ------- Float (1) / Integer (0)
        *    +--- ------- New Version (1) / Old version (0)
        */
       pTScope->trgDataType = data[ptr];
       ptr++;
       sourceType = data[ptr];
       ptr++;
       switch (sourceType)
       {
		   case SOURCE_TYPE_CONTROLBLOCK:
		   {
			   void* blockAddr;
			   uint16 tblIndex, blockId;
			   uint16 elementId = (uint16)data[ptr] | ((uint16)data[ptr + 1U] << 8);
			   uint16 paramId = (uint16)data[ptr + 2U] | ((uint16)data[ptr + 3U] << 8);
			   uint8 error = getBlockParamIndex(TableStruct->TParamTable, paramId, &tblIndex);
			   if (error != ERROR_SUCCESS)
			   {
				   return (1U);
			   }
			   blockAddr = TableStruct->TParamTable[tblIndex].pAdr;
			   blockId = *(uint16*)blockAddr;

			   error = getBlockFunctionIndex(TableStruct->TFncTable, blockId, &tblIndex);
			   if (error != ERROR_SUCCESS)
			   {
				   return (1U);
			   }
			   pTScope->trgAddr = TableStruct->TFncTable[tblIndex].pFGetAddress(blockAddr, elementId);
			   if (pTScope->trgAddr == NULL)
			   {
				   return (1U);
			   }
			   break;
		   }
		   case SOURCE_TYPE_INPORTBLOCK:
		   {
			   uint16 tblIndex;
			   uint16 paramId = (uint16)data[ptr + 2U] | ((uint16)data[ptr + 3U] << 8);
			   uint8 error = getIoParamIndex(TableStruct->inportParamTable, paramId, &tblIndex);
			   if (error != ERROR_SUCCESS)
			   {
				   return (1U);
			   }
			   pTScope->trgAddr = TableStruct->inportParamTable[tblIndex].data;
			   break;
		   }
		   case SOURCE_TYPE_OUTPORTBLOCK:
		   {
			   uint16 tblIndex;
			   uint16 paramId = (uint16)data[ptr + 2U] | ((uint16)data[ptr + 3U] << 8);
			   uint8 error = getIoParamIndex(TableStruct->outportParamTable, paramId, &tblIndex);
			   if (error != ERROR_SUCCESS)
			   {
				   return (1U);
			   }
			   pTScope->trgAddr = *(void**)TableStruct->outportParamTable[tblIndex].data;
			   break;
		   }
		   case SOURCE_TYPE_ADDRESS:
			   pTScope->trgAddr = (void*)((uint32)data[ptr] | ((uint32)data[ptr + 1U] << 8) |
					   ((uint32)data[ptr + 2U] << 16) | ((uint32)data[ptr + 3U] << 24));
			   break;
		   default:
			   return (1U);
       }
       ptr += 4U;

       {
    	   uint8 trgLevelSize = pTScope->trgDataType & 0x0FU;
    	   bool isNewVersion = ((pTScope->trgDataType & 0x80U) != 0U);

    	   switch (trgLevelSize)
    	   {
    	   case 1:
    		   pTScope->trgLevel = (uint8)data[ptr];
    		   break;
    	   case 2:
    		   pTScope->trgLevel = (uint16)((uint16)data[ptr] | ((uint16)data[ptr + 1U] << 8));
    		   break;
    	   case 4:
    		   pTScope->trgLevel = (uint32)((uint32)data[ptr] | ((uint32)data[ptr + 1U] << 8) |
    		   	   ((uint32)data[ptr + 2U] << 16) | ((uint32)data[ptr + 3U] << 24));
    		   break;
    	   case 8:
    		   pTScope->trgLevel = (uint64)((uint64)data[ptr] | ((uint64)data[ptr + 1U] << 8) |
    		   	   ((uint64)data[ptr + 2U] << 16) | ((uint64)data[ptr + 3U] << 24) |
    		       ((uint64)data[ptr + 4U] << 32) | ((uint64)data[ptr + 5U] << 40) |
    		       ((uint64)data[ptr + 6U] << 48) | ((uint64)data[ptr + 7U] << 56));
    		   break;
    	   default:
    		   /* Data size not supported */
    		   return (1U);
    	   }

    	   if (isNewVersion)
    	   {
    	       ptr += trgLevelSize;
    	   }
    	   else
    	   {
    	       pTScope->trgDataType |= 0x20U;
    	       ptr += 4U;
    	   }
       }

	   pTScope->trgDelay = (int32)(uint32)((uint32)data[ptr] | ((uint32)data[ptr + 1U] << 8) | ((uint32)data[ptr + 2U] << 16) | ((uint32)data[ptr + 3U] << 24));
	   pTScope->trgCount = (uint32)getAbsValI32(pTScope->trgDelay);
	   ptr += 4U;

	   pTScope->trgEdge = (tTrgEdgeType)data[ptr];
       ptr++;
       
       /* check if trigger mode information is being sent (compatibility check for previous Scope versions) */
       if (dataLength > ptr)
       {
           /* get current trigger value if trigger mode is set to NORMAL */
           if (data[ptr] == TRG_MODE_NORMAL)
           {
               /* current value @ trg addr = last trg value */
               /* (avoids immediate trg event due to default last */
               /* trg value = 0 and current trg value > trg level */
               pTScope->trgLastValue = getTriggerValue(pTScope);
           }
           else if (data[ptr] == TRG_MODE_AUTO)
           {
               /* No modifications required for AUTO mode */
           }
           else
           {
               /* Unsupported trigger mode */
               return (1U);
           }
       }
       else
       {
           pTScope->trgLastValue = getTriggerValue(pTScope);
       }

	   /* IMPORTANT - DO NOT MOVE THIS SETION TO OTHER PARTS */
	   /* OF THE SAVE FUNCTION */
	   /* 'number of inputs' & 'state' moved to end of save function */
	   /* to avoid undefined behaviour if save function is */
	   /* interrupted by sample time irq & program is executed */
	   /* in sample time irq */
	   pTScope->noChannels = data[1];
	   pTScope->state = (tScopeState)data[0];

       return (0U);
   }
}

/**
 * Returns block element address.
 */
void* Scope_Main_GetAddress(SCOPE_MAIN* block, uint16 elementId)
{
	/* Scope doesn't have any elements so return null pointer */
	void* addr = NULL;
	return (addr);
}


/**
 * This function checks, if the provided (trigger) value causes a trigger event.
 * @param pTScope Scope handle
 * @param curTrgValue Trigger value
 * @retval true Trigger event occurred
 * @retval false No trigger event occurred
 */
static bool isTriggerEvent(SCOPE_MAIN *pTScope, uint64 curTrgValue)
{
	uint8 size = pTScope->trgDataType & 0x0FU;
	bool isFloat = ((pTScope->trgDataType & 0x40U) != 0U);
	bool isEvent = false;
	if (isFloat)
	{
		switch (size)
		{
			case 4:
			{
				float32 trgLastValue = *(float32*)&pTScope->trgLastValue;
				float32 trgLevel = *(float32*)&pTScope->trgLevel;
				float32 curValue = *(float32*)&curTrgValue;
				switch (pTScope->trgEdge)
				{
				case EDGE_RISING:
					isEvent = ((trgLastValue < trgLevel) && (curValue >= trgLevel));
					break;
				case EDGE_FALLING:
					isEvent = ((trgLastValue > trgLevel) && (curValue <= trgLevel));
					break;
				case EDGE_ANY:
				default:
					isEvent = (((trgLastValue < trgLevel) && (curValue >= trgLevel)) ||
					           ((trgLastValue > trgLevel) && (curValue <= trgLevel)));
					break;
				}
				break;
			}
			case 8:
			{
				float64 trgLastValue = *(float64*)&pTScope->trgLastValue;
				float64 trgLevel = *(float64*)&pTScope->trgLevel;
				float64 curValue = *(float64*)&curTrgValue;
				switch (pTScope->trgEdge)
				{
				case EDGE_RISING:
					isEvent = ((trgLastValue < trgLevel) && (curValue >= trgLevel));
					break;
				case EDGE_FALLING:
					isEvent = ((trgLastValue > trgLevel) && (curValue <= trgLevel));
					break;
				case EDGE_ANY:
				default:
					isEvent = (((trgLastValue < trgLevel) && (curValue >= trgLevel)) ||
					           ((trgLastValue > trgLevel) && (curValue <= trgLevel)));
					break;
				}
				break;
			}
		}
	}
	else
	{
		uint8 isSigned = ((pTScope->trgDataType & 0x20U) != 0U);
		if (isSigned)
		{
			switch (size)
			{
				case 1:
				{
					int8 trgLastValue = (int8)pTScope->trgLastValue;
					int8 trgLevel = (int8)pTScope->trgLevel;
					int8 curValue = (int8)curTrgValue;
					switch (pTScope->trgEdge)
					{
					case EDGE_RISING:
						isEvent = ((trgLastValue < trgLevel) && (curValue >= trgLevel));
						break;
					case EDGE_FALLING:
						isEvent = ((trgLastValue > trgLevel) && (curValue <= trgLevel));
						break;
					case EDGE_ANY:
					default:
						isEvent = (((trgLastValue < trgLevel) && (curValue >= trgLevel)) ||
						           ((trgLastValue > trgLevel) && (curValue <= trgLevel)));
						break;
					}
					break;
				}
				case 2:
				{
					int16 trgLastValue = (int16)pTScope->trgLastValue;
					int16 trgLevel = (int16)pTScope->trgLevel;
					int16 curValue = (int16)curTrgValue;
					switch (pTScope->trgEdge)
					{
					case EDGE_RISING:
						isEvent = ((trgLastValue < trgLevel) && (curValue >= trgLevel));
						break;
					case EDGE_FALLING:
						isEvent = ((trgLastValue > trgLevel) && (curValue <= trgLevel));
						break;
					case EDGE_ANY:
					default:
						isEvent = (((trgLastValue < trgLevel) && (curValue >= trgLevel)) ||
						           ((trgLastValue > trgLevel) && (curValue <= trgLevel)));
						break;
					}
					break;
				}
				case 4:
				{
					int32 trgLastValue = (int32)pTScope->trgLastValue;
					int32 trgLevel = (int32)pTScope->trgLevel;
					int32 curValue = (int32)curTrgValue;
					switch (pTScope->trgEdge)
					{
					case EDGE_RISING:
						isEvent = ((trgLastValue < trgLevel) && (curValue >= trgLevel));
						break;
					case EDGE_FALLING:
						isEvent = ((trgLastValue > trgLevel) && (curValue <= trgLevel));
						break;
					case EDGE_ANY:
					default:
						isEvent = (((trgLastValue < trgLevel) && (curValue >= trgLevel)) ||
						           ((trgLastValue > trgLevel) && (curValue <= trgLevel)));
						break;
					}
					break;
				}
				case 8:
				{
					int64 trgLastValue = (int64)pTScope->trgLastValue;
					int64 trgLevel = (int64)pTScope->trgLevel;
					int64 curValue = (int64)curTrgValue;
					switch (pTScope->trgEdge)
					{
					case EDGE_RISING:
						isEvent = ((trgLastValue < trgLevel) && (curValue >= trgLevel));
						break;
					case EDGE_FALLING:
						isEvent = ((trgLastValue > trgLevel) && (curValue <= trgLevel));
						break;
					case EDGE_ANY:
					default:
						isEvent = (((trgLastValue < trgLevel) && (curValue >= trgLevel)) ||
						           ((trgLastValue > trgLevel) && (curValue <= trgLevel)));
						break;
					}
					break;
				}
			}
		}
		else
		{
			switch (size)
			{
				case 1:
				{
					uint8 trgLastValue = (uint8)pTScope->trgLastValue;
					uint8 trgLevel = (uint8)pTScope->trgLevel;
					uint8 curValue = (uint8)curTrgValue;
					switch (pTScope->trgEdge)
					{
					case EDGE_RISING:
						isEvent = ((trgLastValue < trgLevel) && (curValue >= trgLevel));
						break;
					case EDGE_FALLING:
						isEvent = ((trgLastValue > trgLevel) && (curValue <= trgLevel));
						break;
					case EDGE_ANY:
					default:
						isEvent = (((trgLastValue < trgLevel) && (curValue >= trgLevel)) ||
						           ((trgLastValue > trgLevel) && (curValue <= trgLevel)));
						break;
					}
					break;
				}
				case 2:
				{
					uint16 trgLastValue = (uint16)pTScope->trgLastValue;
					uint16 trgLevel = (uint16)pTScope->trgLevel;
					uint16 curValue = (uint16)curTrgValue;
					switch (pTScope->trgEdge)
					{
					case EDGE_RISING:
						isEvent = ((trgLastValue < trgLevel) && (curValue >= trgLevel));
						break;
					case EDGE_FALLING:
						isEvent = ((trgLastValue > trgLevel) && (curValue <= trgLevel));
						break;
					case EDGE_ANY:
					default:
						isEvent = (((trgLastValue < trgLevel) && (curValue >= trgLevel)) ||
						           ((trgLastValue > trgLevel) && (curValue <= trgLevel)));
						break;
					}
					break;
				}
				case 4:
				{
					uint32 trgLastValue = (uint32)pTScope->trgLastValue;
					uint32 trgLevel = (uint32)pTScope->trgLevel;
					uint32 curValue = (uint32)curTrgValue;
					switch (pTScope->trgEdge)
					{
					case EDGE_RISING:
						isEvent = ((trgLastValue < trgLevel) && (curValue >= trgLevel));
						break;
					case EDGE_FALLING:
						isEvent = ((trgLastValue > trgLevel) && (curValue <= trgLevel));
						break;
					case EDGE_ANY:
					default:
						isEvent = (((trgLastValue < trgLevel) && (curValue >= trgLevel)) ||
						           ((trgLastValue > trgLevel) && (curValue <= trgLevel)));
						break;
					}
					break;
				}
				case 8:
				{
					uint64 trgLastValue = (uint64)pTScope->trgLastValue;
					uint64 trgLevel = (uint64)pTScope->trgLevel;
					uint64 curValue = (uint64)curTrgValue;
					switch (pTScope->trgEdge)
					{
					case EDGE_RISING:
						isEvent = ((trgLastValue < trgLevel) && (curValue >= trgLevel));
						break;
					case EDGE_FALLING:
						isEvent = ((trgLastValue > trgLevel) && (curValue <= trgLevel));
						break;
					case EDGE_ANY:
					default:
						isEvent = (((trgLastValue < trgLevel) && (curValue >= trgLevel)) ||
						           ((trgLastValue > trgLevel) && (curValue <= trgLevel)));
						break;
					}
					break;
				}
			}
		} /* isSigned */
	} /* isFloat */
	return (isEvent);
}

/**
 * Reads and returns current trigger value.
 * @param pTScope Scope handle
 * @returns Trigger value
 */
static uint64 getTriggerValue(SCOPE_MAIN *pTScope)
{
	uint64 trgValue;
	uint8 trgLevelSize = pTScope->trgDataType & 0x0FU;
	switch (trgLevelSize)
	{
	case 1:
		trgValue = *(uint8*)pTScope->trgAddr;
		break;
	case 2:
		trgValue = *(uint16*)pTScope->trgAddr;
		break;
	case 4:
		trgValue = *(uint32*)pTScope->trgAddr;
		break;
	case 8:
		trgValue = *(uint64*)pTScope->trgAddr;
		break;
	default:
		/* Unsupported size */
		trgValue = 0U;
		break;
	}
	return (trgValue);
}

/* sample offline data and write it into offline array */
static void sampleData(SCOPE_MAIN *pTScope)
{
    uint8 i, j;

    i = 0U;
    do
    {
        j = 0U;
        do
        {
            *(ALIGNCASTPTR pTScope->arrayAddr + pTScope->offlinePtr) = *(ALIGNCASTPTR pTScope->channelAddr[i] + j);
            pTScope->offlinePtr++;
            j++;
        }
        while (j < pTScope->dataSize[i]);

        i++;
    }
    while(i < pTScope->noChannels);
}
