/****************************************************************
 ****************************************************************
 **                                                            **
 **    (C)Copyright 2005-2006, American Megatrends Inc.        **
 **                                                            **
 **            All Rights Reserved.                            **
 **                                                            **
 **        6145-F, Northbelt Parkway, Norcross,                **
 **                                                            **
 **        Georgia - 30071, USA. Phone-(770)-246-8600.         **
 **                                                            **
 ****************************************************************
 *****************************************************************
 *
 * SensorMonitor.c
 * Sensor Monitor
 *
 * Author: Rama Rao Bisa <ramab@ami.com>
 *
 *****************************************************************/

#include "MsgHndlr.h"
#include "SensorEvent.h"
#include "com_IPMI_SDRRecord.h"
#include "Sensor.h"
#include "sensor_tbl.h"
#include "SEL.h"
#include "Support.h"
#include <time.h>
#include "main.h"
#include "Api.h"

//#if SENSOR_DEVICE == 1

/*** Local Definitions ***/
#define FULL_SDR_REC                0x01
#define COMPACT_SDR_REC             0x02
#define EVENT_MSG_LENGTH            9

#define TEMP_SENSOR_TYPE            0x01
#define VOLT_SENSOR_TYPE            0x02
#define FAN_SENSOR_TYPE             0x04
#define POWER_SENSOR_TYPE           0x08
#define CURRENT_SENSOR_TYPE         0x03
#define MONITOR_ASIC_IC_SENSOR_TYPE 0x26
#define OEM_SENSOR_TYPE             0xC0
#define OTHER_UNITS_SENSOR_TYPE     0x0B

#define LOWER_CRITICAL_GNG_LOW         0x02
#define UPPER_CRITICAL_GNG_HIGH        0x09 
#define LOWER_NON_CRITICAL_GNG_LOW     0x00
#define UPPER_NON_CRITICAL_GNG_HIGH    0x07
#define LOWER_NON_RECOVERABLE_GNG_LOW  0x04 
#define UPPER_NON_RECOVERABLE_GNG_HIGH 0x0B


/*** Prototype Declaration ***/
static void MonitorTSensors ( SensorInfo_T*  pSensorInfo);
static void MonitorNonTSensors ( SensorInfo_T*  pSensorInfo);

/*-------------------------------------------
 * SensorMonitorTask
 *----------------------               --------------------*/
void *SensorMonitorTask (void *pArg)
{
	int    					i;
	SensorInfo_T*        	pSensorInfo;
	SensorSharedMem_T*    	pSMSharedMem;

	printf("SensorMonitorTask start...\r\n");

	g_BMCInfo.SenConfig.MonitorBusy = 0;
	g_BMCInfo.SenConfig.InitAgentRearm = FALSE;
	/* Get the Sensor Shared Memory */
	pSMSharedMem = ( SensorSharedMem_T*)&g_BMCInfo.SensorSharedMem;
	
	g_BMCInfo.SenConfig.ValidSensorCnt			=	SENSOR_NUMBERS;
	
	InitSensorInfo ();
	InitSensorDev();
	
	pSMSharedMem->GlobalSensorScanningEnable 	= 	TRUE;

	pSMSharedMem->SensorTick	=	0;
	while (1)
	{
		g_BMCInfo.SenConfig.InitAgentRearm = FALSE;
		
		/* Monitor all sensors */
		for (i = 0; i < g_BMCInfo.SenConfig.ValidSensorCnt; i++)
		{
			/* Check if Global Scanning Enabled or Disabled */
			if (pSMSharedMem->GlobalSensorScanningEnable)
			{
				pSensorInfo = (SensorInfo_T *)&pSMSharedMem->SensorInfo [i];

				//printf("sensor number: %d, RecordID: %d\n", pSensorInfo->SensorNumber, pSensorInfo->RecordID);
				/* Monitoring cycle */
				if (THRESHOLD_SENSOR_CLASS  == pSensorInfo->EventTypeCode)
				{
					if ((0 == (pSMSharedMem->SensorTick %  pSensorInfo->SensorMonitorInterval)) &&
						(g_BMCInfo.SenConfig.PowerOnTick >= pSensorInfo->PowerOnDelay) &&
						(g_BMCInfo.SenConfig.SysResetTick >= pSensorInfo->SysResetDelay)) 
					{ 
						/* Clear the Error status for this scan */
						pSensorInfo->Err = 0; 
						
						/* Monitor threshold sensor */
						MonitorTSensors (pSensorInfo); 		
					}
				}
				else
				{
					if ((0 == (pSMSharedMem->SensorTick %  pSensorInfo->SensorMonitorInterval)) &&
						(g_BMCInfo.SenConfig.PowerOnTick >= pSensorInfo->PowerOnDelay) &&
						(g_BMCInfo.SenConfig.SysResetTick >= pSensorInfo->SysResetDelay))
					{ 
						/* Clear the Error status for this scan */
						pSensorInfo->Err = 0;
						/* Monitor Non threshold sensor */
						MonitorNonTSensors (pSensorInfo);
						
					}
				}
			}
		}
		g_BMCInfo.SenConfig.MonitorBusy = 0;
		
		sleep(1);
	} 
}

// Return a high deassertion threshold.
// This routine takes into account signed sensors as well as
// values wrapping around boundaries.
static
int16_t GetHighDeassertValue(uint8_t IsSigned, int16_t Value, uint8_t Hysteresis)
{
	int16_t deassertValue = (Value - Hysteresis);
	
	if (FALSE == IsSigned)
	{
		if (deassertValue < 0)
			deassertValue = 0;
	}
	else
	{
		if (deassertValue < -128)
			deassertValue = -128;
	}
	
	return deassertValue;
}

// Return a low deassertion threshold.
// This routine takes into account signed sensors as well as
// values wrapping around boundaries.
static
int16_t GetLowDeassertValue(uint8_t IsSigned, int16_t Value, uint8_t Hysteresis)
{
	int16_t deassertValue = (Value + Hysteresis);
	if (FALSE == IsSigned)
	{
		if (deassertValue > 255)
			deassertValue = 255;
	}
	else
	{
		if (deassertValue > 127)
			deassertValue = 127;
	}
	
	return deassertValue;
}

/**
 * @brief Monitor Threshold sensors.
 * @param i - Sensor index.
**/
static void
MonitorTSensors ( SensorInfo_T*     pSensorInfo)
{
	uint8_t                   EventData1;
	uint8_t                   EventData3;
	uint8_t                   EvData1;
	uint8_t                   SendDeassertion;
	uint8_t                   SendAssertion;
	uint8_t                   EventMsg [EVENT_MSG_LENGTH];
	uint8_t                   Level;
	uint8_t                   HealthLevel;
	uint8_t                   StartLevel;
	int16_t                   Value;
	uint8_t                   AssertionEventOccuredByte1;
	uint8_t                   AssertionEventOccuredByte2;
	uint8_t                   DeassertionEventOccuredByte1;
	uint8_t                   DeassertionEventOccuredByte2;
	uint8_t                   DeassertionEventEnablesByte1;
	uint8_t                   DeassertionEventEnablesByte2;
	uint8_t                   AssertionEventEnablesByte1;
	uint8_t                   AssertionEventEnablesByte2;
	int16_t                   WarningLow;
	int16_t                   WarningHigh;
	uint8_t                   NegHysteresis;
	uint8_t                   PosHysteresis;
	int16_t                   CriticalHigh;
	int16_t                   CriticalLow;
	int16_t                   NonRecoverableHigh;
	int16_t                   NonRecoverableLow;
//	uint8_t                   SensorLevel;
	uint8_t                   SettableThreshMask;
	uint8_t		    	 	  SensorReading;
	uint8_t  		    		PSGood = 0;

	uint8_t                       AssertionHistoryByte1;
	uint8_t                       AssertionHistoryByte2;
	uint8_t                       DeassertionHistoryByte1;
	uint8_t                       DeassertionHistoryByte2;
	uint8_t                   OEMField;
//	uint8_t			    	SensorNum;	
	uint8_t                	SignedSensor = 0; // 1 if sensor has signed values
	int16_t               	SensorMax = 255;
	int16_t               	SensorMin = 0;
	//uint16_t_t              OrgSensorValue;
	int16_t               	DeassertThreshold;
	// Added for Sensor Override capability
//	int                 	Override = 0;
//	uint8_t 				ReadFlags = 0;
//	FullSensorRec_T*      	sfs=NULL;
//	CompactSensorRec_T*   	scs=NULL;
	int				index,j;
	
	PSGood = g_BMCInfo.PowerGoodFlag;
 

	/* If sensor is not need to monitor on stand by power, and if Server */
	/* is power off then return setting error "sensor not acceble at present state" */
	if  (( 0 == (pSensorInfo->SensorState & 0x1) ) && ( 0 == PSGood)) 
	{
		// Response cannot be provided in this state
		pSensorInfo->Err = CC_PARAM_NOT_SUP_IN_CUR_STATE ; 
		pSensorInfo->EventFlags |= BIT5;
		return;
	}
	else
	{
		pSensorInfo->Err	=	get_sensor_reading(pSensorInfo->SensorNumber, &SensorReading);
		
//		if (FULL_SDR_REC == pSensorInfo->SDRRec->Type)
//		{
//			sfs = ( FullSensorRec_T*)pSensorInfo->SDRRec;
//		}
//		else if (COMPACT_SDR_REC==pSensorInfo->SDRRec->Type)
//		{
//			scs = ( CompactSensorRec_T*)pSensorInfo->SDRRec;
//		}
		pSensorInfo->SensorReading = SensorReading;
		
		//keep sensor history
		if((g_BMCInfo.CurTimerSecond%180 == 0))	//3 minutes
		{
			for(index=0; index<SENSOR_NUMBERS;index++)
			{
				if(pSensorInfo->SensorNumber == gSensorHistoryInfo[index].SensorNum)
				{
					for(j=1;j<HISTORY_DATA_SIZE;j++)
					{
						gSensorHistoryInfo[index].History[j-1] =  gSensorHistoryInfo[index].History[j];
					}
					gSensorHistoryInfo[index].History[HISTORY_DATA_SIZE-1] = pSensorInfo->SensorReading;
				}
			}
		}
		
	}


	if (0 == pSensorInfo->Err)
	{
		pSensorInfo->EventFlags &= ~BIT5;
	}
	else
	{
		pSensorInfo->EventFlags |= BIT5;
	}
	
	do
	{
		EvData1                      = 0;
		EventData1                   = 0;
		EventData3                   = 0;
		SendDeassertion              = 0;
		SendAssertion                = 0;
		//SensorLevel                  = 0;
		Level                        = pSensorInfo->EventLevel;
		Value                        = pSensorInfo->SensorReading;
		AssertionEventOccuredByte1   = pSensorInfo->AssertionEventOccuredByte1;
		AssertionEventOccuredByte2   = pSensorInfo->AssertionEventOccuredByte2;
		DeassertionEventOccuredByte1 = pSensorInfo->DeassertionEventOccuredByte1;
		DeassertionEventOccuredByte2 = pSensorInfo->DeassertionEventOccuredByte2;
		AssertionEventEnablesByte1   = pSensorInfo->AssertionEventEnablesByte1;
		AssertionEventEnablesByte2   = pSensorInfo->AssertionEventEnablesByte2;
		DeassertionEventEnablesByte1 = pSensorInfo->DeassertionEventEnablesByte1;
		DeassertionEventEnablesByte2 = pSensorInfo->DeassertionEventEnablesByte2;
		WarningLow                   = pSensorInfo->LowerNonCritical;
		WarningHigh                  = pSensorInfo->UpperNonCritical;
		NegHysteresis                = pSensorInfo->NegHysteresis;
		PosHysteresis                = pSensorInfo->PosHysteresis;
		CriticalHigh                 = pSensorInfo->UpperCritical;
		CriticalLow                  = pSensorInfo->LowerCritical;
		NonRecoverableHigh           = pSensorInfo->UpperNonRecoverable;
		NonRecoverableLow            = pSensorInfo->LowerNonRecoverable;
		OEMField					 = pSensorInfo->OEMField;
//		SensorNum					 = pSensorInfo->SensorNumber;

		if(1==OEMField)
		{
			SensorAverage(pSensorInfo->SensorNumber, &pSensorInfo->SensorReading);
		}

		SettableThreshMask           = (uint8_t)(pSensorInfo->SettableThreshMask >> 8);

		SignedSensor = (0 != (pSensorInfo->Units1 & 0xC0));	//Analog data format
		if (SignedSensor)
		{
			// These are max and min sensor readings for a signed sensor
			SensorMax =  127;
			SensorMin = -128;

			//
			// All Thresholds and the sensor value need to be sign extended to 16 bits
			// for signed sensors (if the value is negative).
			//
			WarningLow                = (int16_t)((int8_t)pSensorInfo->LowerNonCritical);
			WarningHigh               = (int16_t)((int8_t)pSensorInfo->UpperNonCritical);
			CriticalHigh                 = (int16_t)((int8_t)pSensorInfo->UpperCritical);
			CriticalLow                  = (int16_t)((int8_t)pSensorInfo->LowerCritical);
			NonRecoverableHigh    = (int16_t)((int8_t)pSensorInfo->UpperNonRecoverable);
			NonRecoverableLow     = (int16_t)((int8_t)pSensorInfo->LowerNonRecoverable);
			Value                          = (int16_t)((int8_t)pSensorInfo->SensorReading);
		}

		//
		// For unused thresholds, set them to a value that the sensor value cannot
		// have in an 8 bit value so no match can happen.
		//
		if (0 == (SettableThreshMask & BIT5))
		{
			// Set to a value that the sensor cannot have
			NonRecoverableHigh = SensorMax + 1;
		}
		if (0 == (SettableThreshMask & BIT2))
		{
			// Set to a value that the sensor cannot have
			NonRecoverableLow = SensorMin - 1;
		}
		if (0 == (SettableThreshMask & BIT4))
		{
			CriticalHigh = NonRecoverableHigh;
		}
		if (0 == (SettableThreshMask & BIT1))
		{
			CriticalLow  = NonRecoverableLow;
		}
		if (0 == (SettableThreshMask & BIT3))
		{
			WarningHigh = CriticalHigh;
		}
		if (0 == (SettableThreshMask & BIT0))
		{
			WarningLow = CriticalLow;
		}

		StartLevel = Level;

		switch (Level)
		{
			case SENSOR_STATUS_NORMAL:
				if (Value <= WarningLow)
				{
					//sensor_dbg_printf("#%02x LNC(A) - Value: %02x Threshold: %02x\r\n", (pSensorInfo->SensorNumber), (uint8_t)Value, (uint8_t)WarningLow);
					/* deassert WarningLow going High */
					EvData1 = 0x51;
					if (DeassertionEventEnablesByte1 & 0x02)
					{
						SendDeassertion = 1;
					}
					/* remove WarnignLow going Low deassertion */
					DeassertionEventOccuredByte1 &= ~0x01;
					/* deassert WarningLow going High */
					DeassertionEventOccuredByte1 |= 0x02;

					/* assert WarningLow going Low */
					EventData1 = 0x50;
					if(AssertionEventEnablesByte1 & 0x01)
					{
						SendAssertion = 1;
					}
					Level = SENSOR_STATUS_WARNING_LOW;
					EventData3 = WarningLow;
					/* set de/assertion event */
					/* remove WarningLow going High assertion */
					AssertionEventOccuredByte1 &= ~0x02;
					/* assert WarningLow going Low */
					AssertionEventOccuredByte1 |= 0x01;
					//SensorLevel = LWR_NON_CRITICAL_GOING_LOW_CTRL_FN;
				}
				if (Value >= WarningHigh)
				{
					//sensor_dbg_printf("#%02x UNC(A) - Value: %02x Threshold: %02x\n", pSensorInfo->SensorNumber, (uint8_t)Value, (uint8_t)WarningHigh);
					/* deassert WarningHigh going Low */
					EvData1 = 0x56;
					if (DeassertionEventEnablesByte1 & 0x40)
					{
						SendDeassertion = 1;
					}

					/* remove WarningHigh going High deassertion */
					DeassertionEventOccuredByte1 &= ~0x80;
					/*  deassert WarningHigh going Low */
					DeassertionEventOccuredByte1 |= 0x40;

					/* assert WarningHigh going High */
					EventData1 = 0x57;
					if (AssertionEventEnablesByte1 & 0x80)
					{
						SendAssertion = 1;
					}
					/* set de/assertion occured */
					/* remove WarningHigh going Low assertion */
					AssertionEventOccuredByte1 &= ~0x40;
					/* assert WarningHigh going High */
					AssertionEventOccuredByte1 |= 0x80;
					Level = SENSOR_STATUS_WARNING_HIGH;
					/* Threshold that caused event */
					EventData3 = WarningHigh;
					//SensorLevel = UPPER_NON_CRITICAL_GOING_HIGH_CTRL_FN;
				}
				break;

			case SENSOR_STATUS_WARNING_HIGH:
				DeassertThreshold = GetHighDeassertValue(SignedSensor, WarningHigh, PosHysteresis);
				if(Value < DeassertThreshold)
				{
					//sensor_dbg_printf("#%02x UNC(D) - Value: %02x Threshold: %02x\n", pSensorInfo->SensorNumber, (uint8_t)Value, (uint8_t)DeassertThreshold);
					/* deassert WarningHigh going High */
					EvData1 = 0x57;
					if (DeassertionEventEnablesByte1 & 0x80)
					{
						SendDeassertion = 1;
					}
					/* remove WarningHigh going Low deassertion */
					DeassertionEventOccuredByte1 &= ~0x40;
					/* deassert WarningHigh going High */
					DeassertionEventOccuredByte1 |= 0x80;

					/* assert WaningHigh going Low */
					EventData1 = 0x56;
					if (AssertionEventEnablesByte1 & 0x40)
					{
						SendAssertion = 1;
					}
					Level = SENSOR_STATUS_NORMAL;
					EventData3 = WarningHigh;
					/* remove WarningHigh going High assertion */
					AssertionEventOccuredByte1 &= ~0x80;
					/* assert WarningHigh going Low */
					AssertionEventOccuredByte1 |= 0x40;
				    //SensorLevel = UPPER_NON_CRITICAL_GOING_LOW_CTRL_FN;
				}
				if (Value >= CriticalHigh)
				{
					//sensor_dbg_printf("#%02x UC(A) - Value: %02x Threshold: %02x\n", pSensorInfo->SensorNumber, (uint8_t)Value, (uint8_t)CriticalHigh);
					/* deassert CriticalHigh going Low */
					EvData1 = 0x58;
					if (DeassertionEventEnablesByte2 & 0x01)
					{
						SendDeassertion = 1;
					}

					/* remove CriticalHigh going High deassertion */
					DeassertionEventOccuredByte2 &= ~0x02;
					/* deassert CriticalHigh going Low */
					DeassertionEventOccuredByte2 |= 0x01;
					/*  assert CriticalHigh going High */
					EventData1 = 0x59;
					if (AssertionEventEnablesByte2 & 0x02)
					{
						SendAssertion = 1;
					}
					Level = SENSOR_STATUS_CRITICAL_HIGH;
					EventData3 = CriticalHigh;
					/* set de/assertion event occured */
					/* remove CriticalHigh going Low assertion */
					AssertionEventOccuredByte2 &= ~0x01;
					/* assert CriticalHigh going High */
					AssertionEventOccuredByte2 |= 0x02;
					//SensorLevel = UPPER_CRITICAL_GOING_HIGH_CTRL_FN;
				}
				break;

			case SENSOR_STATUS_WARNING_LOW:
				DeassertThreshold = GetLowDeassertValue(SignedSensor, WarningLow, NegHysteresis);
				if (Value > DeassertThreshold)
				{
					//sensor_dbg_printf("#%02x LNC(D) - Value: %02x Threshold: %02x\n", pSensorInfo->SensorNumber, (uint8_t)Value, (uint8_t)DeassertThreshold);
					/* deassert WarningLow going Low */
					EvData1 = 0x50;
					if (DeassertionEventEnablesByte1 & 0x01)
					{
						SendDeassertion = 1;
					}

					/* remove WarningLow going High deassertion */
					DeassertionEventOccuredByte1 &= ~0x02;
					/* deassert WarningLow going Low */
					DeassertionEventOccuredByte1 |= 0x01;

					/* assert WarningLow going High */
					EventData1 = 0x51;
					if (AssertionEventEnablesByte1 & 0x02)
					{
						SendAssertion = 1;
					}
					Level = SENSOR_STATUS_NORMAL;
					EventData3 = WarningLow;
					/* set de/assertion event */
					/* remove WarningLow going Low assertion */
					AssertionEventOccuredByte1 &= ~0x01;
					/* assert WarningLow going High */
					AssertionEventOccuredByte1 |= 0x02;
					//SensorLevel = LWR_NON_CRITICAL_GOING_HIGH_CTRL_FN;
				}
				if (Value <= CriticalLow)
				{
					//sensor_dbg_printf("#%02x LC(A) - Value: %02x Threshold: %02x\n", pSensorInfo->SensorNumber, (uint8_t)Value, (uint8_t)CriticalLow);
					/* deassert CriticalLow going High */
					EvData1 = 0x53;
					if (DeassertionEventEnablesByte1 & 0x08)
					{
						SendDeassertion = 1;
					}

					/* remove CriticalLow going Low deassertion */
					DeassertionEventOccuredByte1 &= ~0x04;
					/* deassert CriticalHigh going High */
					DeassertionEventOccuredByte1 |= 0x08;

					/* assert CriticalLow going Low */
					EventData1 = 0x52;
					if (AssertionEventEnablesByte1 & 0x04)
					{
						SendAssertion = 1;
					}
					Level = SENSOR_STATUS_CRITICAL_LOW;
					EventData3 = CriticalLow;
					/* remove CriticalLow going High assertion */
					AssertionEventOccuredByte1 &= ~0x08;
					/* assert CriticalLow going Low */
					AssertionEventOccuredByte1 |= 0x04;
					//SensorLevel = LWR_CRITICAL_GOING_LOW_CTRL_FN;
				}
				break;

			case SENSOR_STATUS_CRITICAL_HIGH:
				DeassertThreshold = GetHighDeassertValue(SignedSensor, CriticalHigh, PosHysteresis);
				if (Value < DeassertThreshold)
				{
					//sensor_dbg_printf("#%02x UC(D) - Value: %02x Threshold: %02x\n",pSensorInfo->SensorNumber, (uint8_t)Value, (uint8_t)DeassertThreshold);
					/* deassert CriticalHigh going High */
					EvData1 = 0x59;
					if (DeassertionEventEnablesByte2 & 0x02)
					{
						SendDeassertion = 1;
					}

					/* remove CriticalHigh going Low deassertion */
					DeassertionEventOccuredByte2 &= ~0x01;
					/* deassert CriticalHigh going High */
					DeassertionEventOccuredByte2 |= 0x02;

					/* assert CriticalHigh going Low */
					EventData1 = 0x58;
					if (AssertionEventEnablesByte2 & 0x01)
					{
						SendAssertion = 1;
					}
					Level = SENSOR_STATUS_WARNING_HIGH;
					EventData3 = CriticalHigh;
					/* set de/assertion event occured */
					/* remove CriticalHigh going High assertion */
					AssertionEventOccuredByte2 &= ~0x02;
					/* assert CriticalHigh going Low */
					AssertionEventOccuredByte2 |= 0x01;
					//SensorLevel = UPPER_CRITICAL_GOING_LOW_CTRL_FN;
				}
				if (Value >= NonRecoverableHigh)
				{
					//sensor_dbg_printf("#%02x UNR(A) - Value: %02x Threshold: %02x\n", pSensorInfo->SensorNumber, (uint8_t)Value, (uint8_t)NonRecoverableHigh);
					/*  deassert NonRecoverableHigh going Low */
					EvData1 = 0x5A;
					if (DeassertionEventEnablesByte2 & 0x04)
					{
						SendDeassertion = 1;
					}
					/* remove NonRecoverableHigh going High deassertion */
					DeassertionEventOccuredByte2 &= ~0x08;
					/* deassert NonRecoverableHigh going Low */
					DeassertionEventOccuredByte2 |= 0x04;

					/* assert NonRecoverableHigh going High */
					EventData1 = 0x5B;
					if (AssertionEventEnablesByte2 & 0x08)
					{
						SendAssertion = 1;
					}
					Level = SENSOR_STATUS_NONRECOVERABLE_HIGH;
					EventData3 = NonRecoverableHigh;
					/* remove NonRecoverableHigh going Low assertion */
					AssertionEventOccuredByte2 &= ~0x04;
					/* assert NonRecoverableHigh going High */
					AssertionEventOccuredByte2 |= 0x08;
					//SensorLevel = UPPER_NON_RECOVERABLE_GOING_HIGH_CTRL_FN;
				}
				break;

			case SENSOR_STATUS_CRITICAL_LOW:
				DeassertThreshold = GetLowDeassertValue(SignedSensor, CriticalLow, NegHysteresis);
				if (Value > DeassertThreshold)
				{
					//sensor_dbg_printf("#%02x LC(D) - Value: %02x Threshold: %02x\n",pSensorInfo->SensorNumber, (uint8_t)Value, (uint8_t)DeassertThreshold);
					/* deassert CriticalLow going Low */
					EvData1 = 0x52;
					if (DeassertionEventEnablesByte1 & 0x04)
					{
						SendDeassertion = 1;
					}

					/* remove CriticalLow going High deassertion */
					DeassertionEventOccuredByte1 &= ~0x08;
					/* deassert CriticalLow going Low */
					DeassertionEventOccuredByte1 |= 0x04;

					/* assert CriticalLow going High */
					EventData1 = 0x53;
					if (AssertionEventEnablesByte1 & 0x08)
					{
						SendAssertion = 1;
					}
					Level = SENSOR_STATUS_WARNING_LOW;
					EventData3 = CriticalLow;
					/* remove CriticalLow going Low assertion */
					AssertionEventOccuredByte1 &= ~0x04;
					/* assert CriticalLow going High */
					AssertionEventOccuredByte1 |= 0x08;
					//SensorLevel = LWR_CRITICAL_GOING_HIGH_CTRL_FN;
				}
				if (Value <= NonRecoverableLow)
				{
					//sensor_dbg_printf("#%02x LNR(A) - Value: %02x Threshold: %02x\n", pSensorInfo->SensorNumber, (uint8_t)Value, (uint8_t)NonRecoverableLow);
					/* deassert NonRecoverableLow going High */
					EvData1 = 0x55;
					if (DeassertionEventEnablesByte1 & 0x20)
					{
						SendDeassertion = 1;
					}

					/* remove NonRecoverableLow going Low deassertion */
					DeassertionEventOccuredByte1 &= ~0x10;
					/* deassert NonRecoverableLow going High */
					DeassertionEventOccuredByte1 |= 0x20;

					/* assert NonRecoverableLow going Low */
					EventData1 = 0x54;
					if (AssertionEventEnablesByte1 & 0x10)
					{
						SendAssertion = 1;
					}
					Level = SENSOR_STATUS_NONRECOVERABLE_LOW;
					EventData3 = NonRecoverableLow;
					/* remove NonRecoverableLow going High assertion */
					AssertionEventOccuredByte1 &= ~0x20;
					/* assert NonRecoverableLow going Low */
					AssertionEventOccuredByte1 |= 0x10;
					//SensorLevel = LWR_NON_RECOVERABLE_GOING_LOW_CTRL_FN;
				}
				break;

			case SENSOR_STATUS_NONRECOVERABLE_HIGH:
				DeassertThreshold = GetHighDeassertValue(SignedSensor, NonRecoverableHigh, PosHysteresis);
				if (Value < DeassertThreshold)
				{
					//sensor_dbg_printf("#%02x UNR(D) - Value: %02x Threshold: %02x\n", pSensorInfo->SensorNumber, (uint8_t)Value, (uint8_t)DeassertThreshold);
					/* deassert NonRecoverableHigh going High */
					EvData1 = 0x5B;
					if (DeassertionEventEnablesByte2 & 0x08)
					{
						SendDeassertion = 1;
					}

					/* remove NonRecoverableHigh going Low deassertion */
					DeassertionEventOccuredByte2 &= ~0x04;
					/* deassert NonRecoverableHigh going High */
					DeassertionEventOccuredByte2 |= 0x08;

					/* assert NonRecoverableHigh going Low */
					EventData1 = 0x5A;
					if (AssertionEventEnablesByte2 & 0x04)
					{
						SendAssertion = 1;
					}
					Level = SENSOR_STATUS_CRITICAL_HIGH;
					EventData3 = NonRecoverableHigh;
					/* remove NonRecoverableHigh going High assertion */
					AssertionEventOccuredByte2 &= ~0x08;
					/* assert NonRecoverableHigh going Low */
					AssertionEventOccuredByte2 |= 0x04;
					//SensorLevel = UPPER_NON_RECOVERABLE_GOING_LOW_CTRL_FN;
				}
				break;

			case SENSOR_STATUS_NONRECOVERABLE_LOW:
				DeassertThreshold = GetLowDeassertValue(SignedSensor, NonRecoverableLow, NegHysteresis);
				if (Value > DeassertThreshold)
				{
					//sensor_dbg_printf("#%02x LNR(D) - Value: %02x Threshold: %02x\n", pSensorInfo->SensorNumber, (uint8_t)Value, (uint8_t)DeassertThreshold);
					/* deassert NonRecoverableLow going Low */
					EvData1 = 0x54;
					if (DeassertionEventEnablesByte1 & 0x10)
					{
						SendDeassertion = 1;
					}

					/* remove NonRecoverableLow going High deassertion */
					DeassertionEventOccuredByte1 &= ~0x20;
					/* deassert NonRecoverableLow going Low */
					DeassertionEventOccuredByte1 |= 0x10;

					/* assert NonRecoverableLow going High */
					EventData1 = 0x55;
					if (AssertionEventEnablesByte1 & 0x20)
					{
						SendAssertion = 1;
					}
					Level = SENSOR_STATUS_CRITICAL_LOW;
					EventData3 = NonRecoverableLow;
					/* remove NonRecoverableLow going Low assertion */
					AssertionEventOccuredByte1 &= ~0x10;
					/* assert NonRecoverableLow going High */
					AssertionEventOccuredByte1 |= 0x20;
					//SensorLevel = LWR_NON_RECOVERABLE_GOING_HIGH_CTRL_FN;
				}
				break;

			case SENSOR_STATUS_FATAL:
				break;

		} /* switch(m_SensorEventLevel[i]) */

		pSensorInfo->EventLevel = Level;
		pSensorInfo->AssertionEventOccuredByte1 = AssertionEventOccuredByte1;
		pSensorInfo->AssertionEventOccuredByte2 = AssertionEventOccuredByte2;
		pSensorInfo->DeassertionEventOccuredByte1 = DeassertionEventOccuredByte1;
		pSensorInfo->DeassertionEventOccuredByte2 = DeassertionEventOccuredByte2;

		AssertionHistoryByte1   = 0;
		AssertionHistoryByte2   = 0;
		DeassertionHistoryByte1 = 0;
		DeassertionHistoryByte2 = 0;
		
		//TODO: post event message to SEL Task.
		EventMsg [0] = 0x20;
		EventMsg [1] = (pSensorInfo->SensorOwnerLun & 0x03);	/* Multi-LUN support */
		/* EvMRev */
		EventMsg [2] = IPMI_EVM_REVISION;
		/* sensor type */
		EventMsg [3] = pSensorInfo->SensorTypeCode;
		/* sensor number */
		EventMsg [4] = pSensorInfo->SensorNumber;

		/* event direction|type */
		EventMsg [5] = 0x01;

		EventMsg [6] = 0;	

		/* Set Sensor Event Data based on the Operation byte */
		switch (pSensorInfo->Operation>>6)
		{
			case WRITE_NO_EVTDATA1:
				/* Event Data 1 */
				EventMsg [6] =  pSensorInfo->EvtData1;
				/* Intentional Fall thru */
			case WRITE_EVTDATA1:
				/* Event Data 1 */
				EventMsg [6] |= EventData1;
				/* Update EvtData fields */
				/* Current Reading */
				EventMsg [7] = pSensorInfo->EvtData2;
				/* Trigger that caused event */
				EventMsg [8] = pSensorInfo->EvtData3;
				break;

			case USE_SM_EVTDATA:
				/* Event Data 1 */
				EventMsg [6] = EventData1;
				/* Current Reading */
				EventMsg [7] = Value;
				/* Trigger that caused event */
				EventMsg [8] = EventData3;
				break;
		}

		if (SendAssertion)
		{
			if ((EventData1 & 0x0f) < 8)    
			{
				AssertionHistoryByte1 = (1 << (EventData1 & 0x0f));
			}
			else
			{
				AssertionHistoryByte2 = (1 << ((EventData1 & 0x0f) - 8));
			}

			/* For Manual Rearm Sensor - Check for already generated events in the History bytes 
			For Auto Rearm Sensor -History bytes are not valid */
			if ( (0 == (AssertionHistoryByte1 & pSensorInfo->AssertionHistoryByte1)) &&
				(0 == (AssertionHistoryByte2 & pSensorInfo->AssertionHistoryByte2)) )
			{
				/* if sensor is manual arming */
				if (0 == (pSensorInfo->SensorCaps & BIT6))
				{
					/* Update assertion History */
					pSensorInfo->AssertionHistoryByte1 |= AssertionHistoryByte1;
					pSensorInfo->AssertionHistoryByte2 |= AssertionHistoryByte2;
				}
				
				/* Is event message generation enabled ? */
				if (0 != (pSensorInfo->EventFlags & BIT7))
				{
					/* Post Event Message */
					PostEventMessage (EventMsg, sizeof (EventMsg));
				}
			}
			SendAssertion = 0;
		}
		
		if (SendDeassertion)
		{
			if ((EvData1 & 0x0f) < 8)    
			{
				DeassertionHistoryByte1 = (1 << (EvData1 & 0x0f));
			}
			else
			{
				DeassertionHistoryByte2 = (1 << ((EvData1 & 0x0f) - 8));
			}

			/* For Manual Rearm Sensor - Check for already generated events in the History bytes 
			For Auto Rearm Sensor -History bytes are not valid */
			if ( (0 == (DeassertionHistoryByte1 & pSensorInfo->DeassertionHistoryByte1)) &&
			(0 == (DeassertionHistoryByte2 & pSensorInfo->DeassertionHistoryByte2)) )
			{

				/* Event Data 1 */
				EventMsg [6] = EvData1;
				EventMsg [5] = 0x81;

				/* if sensor is manual arming */
				if (0 == (pSensorInfo->SensorCaps & BIT6))
				{
					/* Update Deassertion History */
					pSensorInfo->DeassertionHistoryByte1 |= DeassertionHistoryByte1;
					pSensorInfo->DeassertionHistoryByte2 |= DeassertionHistoryByte2;
				}
					/* Call PreEventLog hook function(s) and don't do
					sensor SEL event log if the return is not zero */
					if (0 != (pSensorInfo->EventFlags & BIT7))
					{						
						/* Post Event Message Here */
						PostEventMessage (EventMsg, sizeof (EventMsg));
					}
			}
			SendDeassertion = 0;
		}
	}while (StartLevel != Level);

	/* Auto Rearm sensor: Get current assertions */
	AssertionHistoryByte1 = pSensorInfo->AssertionEventOccuredByte1;
	AssertionHistoryByte2 = pSensorInfo->AssertionEventOccuredByte2;

	// The following checks need to be done from lowest severity to highest.
	HealthLevel = SENSOR_STATUS_NORMAL;
	if (0 != (AssertionHistoryByte1 & 0x01 & AssertionEventEnablesByte1))
		HealthLevel = SENSOR_STATUS_WARNING_LOW;
	if (0 != (AssertionHistoryByte1 & 0x80 & AssertionEventEnablesByte1))
		HealthLevel = SENSOR_STATUS_WARNING_HIGH;
	if (0 != (AssertionHistoryByte1 & 0x04 & AssertionEventEnablesByte1))
		HealthLevel = SENSOR_STATUS_CRITICAL_LOW;
	if (0 != (AssertionHistoryByte2 & 0x02 & AssertionEventEnablesByte2))
		HealthLevel = SENSOR_STATUS_CRITICAL_HIGH;
	if (0 != (AssertionHistoryByte1 & 0x10 & AssertionEventEnablesByte1))
		HealthLevel = SENSOR_STATUS_NONRECOVERABLE_LOW;
	if (0 != (AssertionHistoryByte2 & 0x08 & AssertionEventEnablesByte2))
		HealthLevel = SENSOR_STATUS_NONRECOVERABLE_HIGH;

	pSensorInfo->HealthLevel = HealthLevel;

	// Make sure the "Reading Not Available" bit is clear.
	pSensorInfo->EventFlags &= ~BIT5;
}


/**
 * @brief Monitor Non-threshold sensors.
 * @param i - Sensor index.
*/
static void
MonitorNonTSensors ( SensorInfo_T*  pSensorInfo)
{
	//TODO:
	printf("MonitorNonTSensors: not implement\r\n");
	
}

/**
 * @fn hal_read_sensor
 * @brief This function reads the sensor reading for given sensor number
 *
**/
int get_sensor_reading (uint8_t sensor_num, uint8_t *preading)
{
    sensor_tbl_t    *pdev_tbl;

    pdev_tbl = (sensor_tbl_t*)getSensorDev (sensor_num);

    if (pdev_tbl == NULL)
    {
        printf ("Error: couldn't find sensor %x\n", sensor_num);
        return 1;
    }


    /* Execute at the requested sensor reading handler */
    if (0 != pdev_tbl->device_read (preading))
    {
        printf ("Error executing read function\n");
        return -1;
    }
     

    //printf ("sensor number %x  reading = %x\r\n", sensor_num, *preading);
    return 0;
}

//<<KAMAL>>Added to support Sensor Averaging ../

#define AVERAGING_SIZE					10
int SensorAverage(uint8_t SensorNum, uint8_t* pSensorReading)
{
    static uint8_t	AverageBuf [AVERAGING_SIZE];
    static int		AverageCount = 0;
    static int		InitDone	   = 0;
    SensorInfo_T*	pSensorInfo    = NULL;
    int 			AverageIndex   = 0;
    int 			i   		   = 0;
    uint32_t		AverageSum	   = 0;

    pSensorInfo = getSensorInfo(SensorNum);
    /* Check if we received valid sensor information */
    if (pSensorInfo == NULL) 
    {
		printf ("Error: Unable to get SensorInfo \n");
		return 0;  
    }		

	/* Averaging index */
	AverageIndex = AverageCount % AVERAGING_SIZE;
	
	/* Set Sensor state to be update in progress unless
	 * we receive all  AVERAGING_SIZE values */
	if (0 == InitDone) 
	{ 
		/* Settting update in progress */
		pSensorInfo->EventFlags |= BIT1;
		
		/* Checking if we have enough to do averaging */
		if (AverageIndex == (AVERAGING_SIZE -1))
		{
			InitDone = 1;
		}
	}
	else
	{
		/* Clearing update in progress */
		pSensorInfo->EventFlags &= ~BIT1;
	}
	
	/* Update averaging buffer */	
	AverageBuf [AverageIndex ] = 	*pSensorReading;
	
	AverageCount++;
	
	if (AverageCount == AVERAGING_SIZE) { AverageCount = 0; }
	
	for (i = 0; i <  AVERAGING_SIZE; i++)
	{
		AverageSum += AverageBuf [i];
	}

	if (1 == InitDone)
	{
		*pSensorReading = (uint8_t)(AverageSum / AVERAGING_SIZE);
	}
		
	/* Averaging done */
	return 0;	
}

SensorInfo_T* getSensorInfo(uint8_t sensorNum)
{
	uint16_t i;
	for(i=0;i<g_BMCInfo.SenConfig.ValidSensorCnt;i++)
	{
		if(sensorNum == g_BMCInfo.SensorSharedMem.SensorInfo[i].SensorNumber)
		{
			return &g_BMCInfo.SensorSharedMem.SensorInfo[i];
		}
	}
	
	return NULL;
}





//#endif /*SENSOR_DEVICE == 1*/

