/*
 * Brief:	Get all sensor information.
 * Author:	Jimbo_zhang@outlook.com
 * Data:		2019-4-27
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "goahead.h"

#include "libipmi_AppDevice.h"
#include "libipmi_session.h"
#include "libipmi_errorcodes.h"
#include "libipmi_struct.h"
#include "libipmi_sdr.h"
#include "libipmi_sensor.h"
#include "libipmi_storlead_OEM.h"
#include "com_IPMI_Storlead.h"
#include "libipmi_StorDevice.h"
#include "com_BmcType.h"
#include "com_BMCCfg.h"
#include "com_IPMI_App.h"


OemWebFlags_T g_OemWebFlags;
uint8_t ChassisPrimaryIPMBAddr[BLADE_NUMBERS] = {0X82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, 0x90, 0x92, 0x94};
uint8_t ChassisSecondaryIPMBAddr[BLADE_NUMBERS] = {0X82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, 0x90, 0x92, 0x94};
/*
*@fn IPMICMD_AMIGetSensorInfo
*@brief
*@param pUDSSession - IPMI Session Handle
*@param pAMIGetSensorInfoReq - Pointer to the request of AMI Get SensorInfo command
*@param pAMIGetSensorInfoRes - Pointer to the response of AMI Get SensorInfo command
*@param timeout - Timeout Value
**/
// uint16_t IPMICMD_GetIPMCSensorInfo(IPMI20_UDS_SESSION_T *pUDSSession, AMIGetSensorInfoRes_T *pGetIPMCSensorInfoRes,int timeout)
// {
//  	uint16_t wRet = 0;
	
// 	uint16_t reservation_id;
// 	uint16_t record_id = 0;
// 	uint32_t dwRecordLen;
// 	SenInfo_T SensorInfo;
	
// 	uint8_t SDRData[100] = {0};
// 	uint8_t NextRecIDLS = 0;
// 	uint8_t NextRecIDMS = 0;
// 	uint8_t cnt = 0;
// 	uint8_t timeoutTick = 0;
// 	wRet = IPMICMD_ReserveSDRRepository(pUDSSession, (ReserveSDRRepositoryRes_T*)SDRData, timeout);
// 	if(wRet != 0)
// 	{
// 		printf("Error Reserve SDR Repository\n");
// 		return wRet;
// 	}
	
// 	reservation_id = SDRData[2]<<8 | SDRData[1];
	
// 	do
// 	{
// 		//Get SDR
// 		if(0 != LIBIPMI_HL_GetSDR(pUDSSession, reservation_id, record_id, (GetSDRRes_T*)SDRData, &dwRecordLen, timeout ))
// 		{
// 			printf("---> Get SDR error! record_id = %#x\n", record_id);
// 			return -1;
// 		}
			
// 		NextRecIDLS = SDRData[1];
// 		NextRecIDMS = SDRData[2];
// 		memcpy(&SensorInfo.hdr, &SDRData[3],5/*Sizeof(SDRRecHdr_T)*/);
// 		if(SensorInfo.hdr.Type == 0x01)	//full sensor sdr
// 		{	
// 			SensorInfo.Accuracy_MSB_Exp = SDRData[3+29-1];
// 			//SensorInfo.AssertionEventByte1 = SDRData[3+15-1];
// 			//SensorInfo.AssertionEventByte2 = SDRData[3+16-1];
// 			SensorInfo.B_LSB	= SDRData[3+27-1];
// 			SensorInfo.B_MSB_Accuracy	=	SDRData[3+28-1];
// 			SensorInfo.DeassertionEventByte1	=	SDRData[3+17-1];
// 			SensorInfo.DeassertionEventByte2	=	SDRData[3+18-1];
// 			SensorInfo.EventTypeCode	=	SDRData[3+14-1];
// 			SensorInfo.Linearization	=	SDRData[3+24-1];
// 			SensorInfo.LowerCritical	=	SDRData[3+41-1];
// 			SensorInfo.LowerNonCritical	=	SDRData[3+42-1];
// 			SensorInfo.LowerNonRecoverable	=	SDRData[3+40-1];
// 			SensorInfo.M_LSB	=	SDRData[3+25-1];
// 			SensorInfo.M_MSB_Tolerance	=	SDRData[3+26-1];
// 			SensorInfo.MaxReading	=	SDRData[3+35-1];
// 			SensorInfo.MinReading	=	SDRData[3+36-1];
// 			SensorInfo.OwnerID	=	SDRData[3+6-1];
// 			SensorInfo.OwnerLUN	=	SDRData[3+7-1];
// 			SensorInfo.RExp_BExp	=	SDRData[3+30-1];			
// 			SensorInfo.SensorNumber	=	SDRData[3+8-1];
// 			SensorInfo.SensorTypeCode		=	SDRData[3+13-1];
// 			SensorInfo.Settable_Readable_ThreshMask	=	SDRData[3+20-1]<<8 | SDRData[3+19-1];
// 			SensorInfo.Units1	=	SDRData[3+21-1];
// 			SensorInfo.Units2	=	SDRData[3+22-1];
// 			SensorInfo.Units3	=	SDRData[3+23-1];
// 			SensorInfo.UpperCritical	=	SDRData[3+38-1];
// 			SensorInfo.UpperNonCritical	=	SDRData[3+39-1];
// 			SensorInfo.UpperNonRecoverable = SDRData[3+37-1];
			
// 			memset(SensorInfo.SensorName, 0, 16);
// 			memcpy(SensorInfo.SensorName, &SDRData[3+49-1], SDRData[3+48-1]&0x3f);
			
// 			//get sensor reading
// 			if(0 != IPMICMD_GetSensorReading(pUDSSession, (GetSensorReadingReq_T *)&SensorInfo.SensorNumber, 
// 				(GetSensorReadingRes_T *)SDRData, timeout))
// 			{
// 				printf("---> Get sensorReading error! sensorNum = %#x\n", SensorInfo.SensorNumber);
// 				return -1;
// 			}
// 			SensorInfo.SensorReading = SDRData[1];
// 			SensorInfo.OptionalStatus	=	SDRData[4];
// 			SensorInfo.Flags	=	SDRData[2];
			
// 			SensorInfo.ComparisonStatus = SDRData[3];
// 			if(SensorInfo.EventTypeCode == 0x01)	//threshold
// 			{
// 				//TODO: jimbo
// 				SensorInfo.AssertionEventByte1 = 0x0;
// 				SensorInfo.AssertionEventByte2 = 0x0;
// 				if((SensorInfo.Units1 & 0xc0) == 0x00)	//unsigned
// 				{
// 					if((uint8_t)SensorInfo.SensorReading > (uint8_t)SensorInfo.UpperCritical)
// 						SensorInfo.AssertionEventByte2 |= 0x02;
// 					if((uint8_t)SensorInfo.SensorReading > (uint8_t)SensorInfo.UpperNonCritical)
// 						SensorInfo.AssertionEventByte1 |= 0x80;
// 					if((uint8_t)SensorInfo.SensorReading > (uint8_t)SensorInfo.UpperNonRecoverable)
// 						SensorInfo.AssertionEventByte2 |= 0x08;
// 					if((uint8_t)SensorInfo.SensorReading < (uint8_t)SensorInfo.LowerCritical)
// 						SensorInfo.AssertionEventByte1 |= 0x04;
// 					if((uint8_t)SensorInfo.SensorReading < (uint8_t)SensorInfo.LowerNonCritical)
// 						SensorInfo.AssertionEventByte1 |= 0x01;
// 					if((uint8_t)SensorInfo.SensorReading < (uint8_t)SensorInfo.LowerNonRecoverable)
// 						SensorInfo.AssertionEventByte1 |= 0x10;					
// 				}
// 				else if((SensorInfo.Units1 & 0xc0) == 0x80)	//2's complement
// 				{
// 					if((char)SensorInfo.SensorReading > (char)SensorInfo.UpperCritical)
// 						SensorInfo.AssertionEventByte2 |= 0x02;
// 					if((char)SensorInfo.SensorReading > (char)SensorInfo.UpperNonCritical)
// 						SensorInfo.AssertionEventByte1 |= 0x80;
// 					if((char)SensorInfo.SensorReading > (char)SensorInfo.UpperNonRecoverable)
// 						SensorInfo.AssertionEventByte2 |= 0x08;
// 					if((char)SensorInfo.SensorReading < (char)SensorInfo.LowerCritical)
// 						SensorInfo.AssertionEventByte1 |= 0x04;
// 					if((char)SensorInfo.SensorReading < (char)SensorInfo.LowerNonCritical)
// 						SensorInfo.AssertionEventByte1 |= 0x01;
// 					if((char)SensorInfo.SensorReading < (char)SensorInfo.LowerNonRecoverable)
// 						SensorInfo.AssertionEventByte1 |= 0x10;
// 				}
				
// 			}
			
			
// 			memcpy(((uint8_t*)pGetIPMCSensorInfoRes)+3+sizeof(SenInfo_T)*cnt, &SensorInfo, sizeof(SenInfo_T));
// 			cnt++;
			
// //			printf("cnt: %d, sensorNum: %#x, sensorReading: %#x, OptionStatus = %#x, ComparisonStatus = %#x\n", 
// //					cnt, SensorInfo.SensorNumber, SensorInfo.SensorReading, SensorInfo.OptionalStatus, SensorInfo.ComparisonStatus);
// 		}
		
		
// 		record_id = NextRecIDMS<<8 | NextRecIDLS;
// 		timeoutTick++;
// 		if(timeoutTick > 64)	
// 		{
// 			wRet = -1;
// 			break;
// 		}
// 	}while(record_id != 0xffff);	  
	
// 	if(wRet == 0)
// 		pGetIPMCSensorInfoRes->CompletionCode = 0;
// 	else
// 		pGetIPMCSensorInfoRes->CompletionCode = 255;
	
// 	pGetIPMCSensorInfoRes->Noofentries = cnt;
	
// //	printf("return pGetIPMCSensorInfoRes: ");
// //	for(i=0;i<3+sizeof(SenInfo_T)*cnt;i++)
// //		printf("%#2x ",((uint8_t*)pGetIPMCSensorInfoRes)[i]);
// //	printf("\n");
	
// 	return (wRet);
// }


// uint16_t LIBIPMI_HL_GetIPMCSensorInfo(IPMI20_UDS_SESSION_T *pUDSSession,SenInfo_T *pSensorInfo,uint32_t *nNumSensor,int timeout)
// {
// 	uint16_t wRet = 0;
// 	AMIGetSensorInfoRes_T *pGetIPMCSensorInfoRes;
// 	uint8_t *SensorEntries;
// 	int i;
	
// 	SensorEntries = (uint8_t *)malloc(MAX_SENSOR_INFO_SIZE);
// 	if(SensorEntries == NULL)
// 	{
// 		printf("Memory allocation error in LIBIPMI_HL_AMIGetSELEntires \n");
// 		wRet = 0xFF;
// 		return wRet;
// 	}
	
// 	memset(SensorEntries,0,MAX_SENSOR_INFO_SIZE);
// 	pGetIPMCSensorInfoRes = (AMIGetSensorInfoRes_T *)SensorEntries;
// 	wRet = IPMICMD_GetIPMCSensorInfo(pUDSSession,(AMIGetSensorInfoRes_T *)SensorEntries,timeout);
// 	if(wRet == LIBIPMI_E_SUCCESS)
// 	{
// 		*nNumSensor = pGetIPMCSensorInfoRes->Noofentries;
// 		for(i = 0; i < pGetIPMCSensorInfoRes->Noofentries; i++)
// 		{
// 			memcpy((uint8_t *)&pSensorInfo[i],&SensorEntries[sizeof(AMIGetSensorInfoRes_T) + (i * sizeof(SenInfo_T))],sizeof(SenInfo_T) );
// 		}
// 	}
// 	else
// 	{
// 		printf("error getting sensor info %d\n",wRet);
// 	}
// 	free(SensorEntries);
// 	return (wRet);
// }

uint16_t LIBIPMI_HL_SetFanInfo( IPMI20_UDS_SESSION_T *pUDSSession, uint8_t fanIndex, uint8_t fanMode, uint8_t fanLevel, int timeout)
{
	uint16_t wRet = 0;
	uint8_t	Res[10];
	uint8_t Req[10];
	uint32_t dwResLen;
	Req[0]	= fanIndex;
	Req[1] 	= fanMode;
	Req[2]	= fanLevel;
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,   NETFNLUN_IPMI_STORLEAD, CMD_SET_FAN_INFO,
													(uint8_t*)Req, 3,
													(uint8_t *)Res, &dwResLen,
													timeout);
	return wRet;
}

uint16_t IPMC_SetFanInfo( IPMI20_UDS_SESSION_T *pUDSSession, uint8_t IpmbAddr, uint8_t fanIndex, uint8_t fanMode, uint8_t fanLevel, int timeout)
{
	int wRet = 0;
	uint32_t	dwResLen;
	uint8_t 	Req[10] = {0};
	uint8_t		Res[50] = {0};

	Req[0] = 0x40;	//Track | channel 0
	Req[1] = IpmbAddr;
	Req[2] = NETFNLUN_IPMI_STORLEAD;
	Req[3] = 0x100 - (Req[1] + Req[2])&0xff;	//checksum1
	Req[4] = 0x20;
	Req[5] = 0x10;
	Req[6] = CMD_SET_FAN_INFO;	
	Req[7] = fanIndex;
	Req[8] = fanMode;
	Req[9] = fanLevel;
	Req[10] = 0x100 - (Req[4] + Req[5] + Req[6] + Req[7] + Req[8] + Req[9])&0xff;

	//dwResLen = sizeof(GetDevIDRes_T);
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession, 
											DEFAULT_NET_FN_LUN, CMD_SEND_MSG,
											Req, 11,
											Res, &dwResLen,
											timeout);
	if(( wRet != 0 ) || (Res[6] != 0))
	{
			printf("Error IPMC_SetFanInfo\n");
			return -1;
	}
	return wRet;
}

uint16_t LIBIPMI_HL_GetSysInfo( IPMI20_UDS_SESSION_T *pUDSSession, SysInfo_T *pSysInfo, int timeout)
{
	
	uint16_t wRet = 0;
	uint8_t Req[5];
	uint8_t	Res[MAX_TEXT_LEN+5];
	uint32_t dwResLen;
	uint16_t strLen, remainLen;
	uint16_t offset = 0;

	//get title
	Req[0] = 0;
	Req[1] = 0;
	Req[2] = 0;
	Req[3] = (MAX_TITLE_LEN>>8)&0xff;	//max title len
	Req[4] = MAX_TITLE_LEN&0xff;
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,   
												NETFNLUN_IPMI_STORLEAD, CMD_GET_SYS_INFO,
												(uint8_t*)Req, 5,
												(uint8_t *)Res, &dwResLen,
												timeout);
	if((wRet != 0) || (Res[0] != 0))
	{
		printf("---> get Title error\n");
		return -1;
	}
	strLen = (Res[1]<<8) | Res[2];
	remainLen = (Res[3]<<8) | Res[4];
	memcpy(pSysInfo->title,&Res[5],strLen);

	//get text
	Req[0] = 1;
	Req[1] = 0;
	Req[2] = 0;
	Req[3] = (MAX_TEXT_LEN>>8)&0xff;	//max text len
	Req[4] = MAX_TEXT_LEN&0xff;
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,   
												NETFNLUN_IPMI_STORLEAD, CMD_GET_SYS_INFO,
												(uint8_t*)Req, 5,
												(uint8_t *)Res, &dwResLen,
												timeout);
	if((wRet != 0) || (Res[0] != 0))
	{
		printf("---> get Text error\n");
		return -1;
	}
	strLen = (Res[1]<<8) | Res[2];
	remainLen = (Res[3]<<8) | Res[4];
	memcpy(pSysInfo->text,&Res[5],strLen);
	
	return 0;
}

uint16_t IPMC_GetSysInfo( IPMI20_UDS_SESSION_T *pUDSSession, uint8_t IpmbAddr, SysInfo_T *pSysInfo, int timeout)
{
	
	uint16_t 	wRet = 0;
	uint8_t 	Req[20] = {0};
	uint8_t		Res[MAX_TEXT_LEN+5];
	uint16_t 	strLen, remainLen;
	uint32_t	dwResLen;
	

	//get title
	Req[0] = 0x40;	//Track | channel 0
	Req[1] = IpmbAddr;
	Req[2] = NETFNLUN_IPMI_STORLEAD;
	Req[3] = 0x100 - (Req[1] + Req[2])&0xff;	//checksum1
	Req[4] = 0x20;
	Req[5] = 0x10;
	Req[6] = CMD_GET_SYS_INFO;	
	Req[7] = 0;
	Req[8] = 0;
	Req[9] = 0;
	Req[10] = (MAX_TITLE_LEN>>8)&0xff;	//max title len
	Req[11] = MAX_TITLE_LEN&0xff;
	Req[12] = 0x100 - (Req[4] + Req[5] + Req[6] + Req[7] + Req[8] + Req[9] + Req[10] + Req[11])&0xff;

	//dwResLen = sizeof(GetDevIDRes_T);
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession, 
											DEFAULT_NET_FN_LUN, CMD_SEND_MSG,
											Req, 13,
											Res, &dwResLen,
											timeout);

	if((wRet != 0) || (Res[6] != 0))
	{
		printf("---> get Title error\n");
		return -1;
	}
	strLen = (Res[7]<<8) | Res[8];
	remainLen = (Res[9]<<8) | Res[10];
	memcpy(pSysInfo->title,&Res[11],strLen);

	//get text
	Req[0] = 0x40;	//Track | channel 0
	Req[1] = IpmbAddr;
	Req[2] = NETFNLUN_IPMI_STORLEAD;
	Req[3] = 0x100 - (Req[1] + Req[2])&0xff;	//checksum1
	Req[4] = 0x20;
	Req[5] = 0x10;
	Req[6] = CMD_GET_SYS_INFO;	
	Req[7] = 1;
	Req[8] = 0;
	Req[9] = 0;
	Req[10] = (MAX_TEXT_LEN>>8)&0xff;	//max text len
	Req[11] = MAX_TEXT_LEN&0xff;
	Req[12] = 0x100 - (Req[4] + Req[5] + Req[6] + Req[7] + Req[8] + Req[9] + Req[10] + Req[11])&0xff;

	//dwResLen = sizeof(GetDevIDRes_T);
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession, 
											DEFAULT_NET_FN_LUN, CMD_SEND_MSG,
											Req, 13,
											Res, &dwResLen,
											timeout);
	if((wRet != 0) || (Res[6] != 0))
	{
		printf("---> get Text error\n");
		return -1;
	}
	strLen = (Res[7]<<8) | Res[8];
	remainLen = (Res[9]<<8) | Res[10];
	memcpy(pSysInfo->text,&Res[11],strLen);
	
	return 0;
}


uint16_t
LIBIPMI_HL_GetSensorHistory( IPMI20_UDS_SESSION_T *pUDSSession, sensor_history_st *pSensorHistory_st, int card_index, int sensor_number, int IPMB_ADDR)
{
	printf("---> come in history\n");
	int i = 0;
	//uint8_t	 	RawHistory[MAX_HISTORY_LEN];
	uint16_t    wRet;
	uint32_t    dwResLen;
	uint32_t	sdr_buff_size = 255;
	uint8_t 	Req[5];
	uint8_t 	*Res = (uint8_t*)walloc(MAX_HISTORY_LEN+3);
	int timeout = 3;
	FullSensorRec_T sdr_buffer;
	uint16_t 	offset = 0;
	uint16_t	reqLen = 0, resLen = 0;
	float 		tmpValue;
	//get factors
	LIBIPMI_HL_GetSpecificSDR( pUDSSession, (uint8_t*)&sdr_buffer, &sdr_buff_size, sensor_number, timeout );	
	
	//get history
	// if( pUDSSession->byMediumType == IPMB_MEDIUM )
	// {
	// 	reqLen = 22;	//32 bytes - ipmb message header - response header - checksum2
	// 	do{
	// 		Req[0] = sensor_number;
	// 		Req[1] = (offset>>8)&0xff;
	// 		Req[2] = offset&0xff;
	// 		Req[3] = (reqLen>>8)&0xff;
	// 		Req[4] = reqLen&0xff;
	// 		wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,   0x2e<<2, 0x89,
	// 												(uint8_t*)Req, 5,
	// 												(uint8_t *)Res, &dwResLen,
	// 												timeout);
	// 		if(wRet != 0)
	// 		{
	// 			return -1;
	// 		}
	// 		resLen = (Res[1]<<8) | Res[2];
	// 		if(resLen > MAX_HISTORY_LEN)
	// 		{
	// 			printf("---> response length error: resLen = %#x\n", resLen);
	// 			return -1;
	// 		}
	// 		memcpy(&RawHistory[offset],&Res[3],resLen);
	// 		offset += resLen;
	// 		if(offset >= MAX_HISTORY_LEN)	//get all history datas
	// 		{
	// 			reqLen = 0;
	// 			break;
	// 		}
	// 		reqLen = ((MAX_HISTORY_LEN-offset)>22) ? 22 : (MAX_HISTORY_LEN-offset);		
	// 	}while(reqLen);		
	// }
	// else
	{
		Req[0] = sensor_number;
		Req[1] = 0;
		Req[2] = 0;
		Req[3] = (MAX_HISTORY_LEN>>8)&0xff;
		Req[4] = MAX_HISTORY_LEN & 0xff;
		wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,   
									NETFNLUN_IPMI_STORLEAD, CMD_GET_SENSOR_HISTORY,
									(uint8_t*)Req, 5,
									(uint8_t *)Res, &dwResLen,
									timeout);
		if(wRet != 0)
		{
			return -1;
		}
		
		resLen = (Res[1]<<8) | Res[2];
		if(resLen > MAX_HISTORY_LEN)
		{
			printf("---> response length error: resLen = %#x\n", resLen);
			return -1;
		}
		//memcpy(RawHistory,&Res[3],resLen);
	}
	
	for(i=0;i < 480; i++)
	{
		ipmi_convert_reading( (uint8_t*)&sdr_buffer, Res[3+i], &tmpValue );
		pSensorHistory_st->sensor_history[i] = tmpValue;
		//printf("raw: %#x, float: %f\n", Res[3+i], tmpValue);
	}
	
	memset(pSensorHistory_st->sensor_name, 0,sizeof(pSensorHistory_st->sensor_name));
	memcpy(pSensorHistory_st->sensor_name, sdr_buffer.IDStr, sdr_buffer.IDStrTypeLen&0x3f);
	pSensorHistory_st->sensor_num = sensor_number;

	wfree(Res);

	return 0;
}

// /************************************************* new add **********************************************************************/
int LIBIPMI_HL_GetChassisInfo(IPMI20_UDS_SESSION_T *pUDSSession, OemChassisInfo_T* pChassisInfo, int timeout)
{
	uint8_t pRes[10];
	int wRet = 0;
	uint32_t	dwResLen;
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
							NETFNLUN_IPMI_STORLEAD, CMD_GET_CHASSIS_INFO,
							NULL, 0,
							(uint8_t*)pRes,  &dwResLen,
							timeout);
	if(( wRet != 0 ) || (pRes[0] != 0))
	{
		printf("Error getting Blade Status Info\n");
		memset(pChassisInfo, 0, sizeof(OemChassisInfo_T));
		pChassisInfo->slotNum = BLADE_NUMBERS;
		pChassisInfo->curIndex = 0;
		return -1;
	}
		
	pChassisInfo->slotNum = pRes[1];
	pChassisInfo->isChMC = pRes[2];
	pChassisInfo->chassisManageFnEnable = pRes[3];	//该字段废弃。
	pChassisInfo->curIndex = pRes[4];
	return 0;
}

int LIBIPMI_HL_GetAllBladeStatus(IPMI20_UDS_SESSION_T *pUDSSession, uint8_t chassisManageEn, BladeStatus_T *BladeStatus, int timeout)
{
	int wRet = 0;
	uint32_t	dwResLen;
	uint8_t pRes[BLADE_NUMBERS*sizeof(BladeStatus_T)+1];
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
							NETFNLUN_IPMI_STORLEAD, CMD_GET_ALLBLADE_INFO,
							(uint8_t*)&chassisManageEn, 1,
							(uint8_t*)pRes,  &dwResLen,
							timeout);
	if(( wRet != 0 ) || (pRes[0] != 0))
	{
			printf("Error getting Blade Status Info\n");
			memset(BladeStatus, 0, BLADE_NUMBERS*sizeof(BladeStatus_T));
	}
		
	memcpy(BladeStatus, pRes+1, BLADE_NUMBERS*sizeof(BladeStatus_T));
	return 0;
}


int LIBIPMI_HL_GetFanInfo(IPMI20_UDS_SESSION_T *pUDSSession, FanInfo_T* pFanInfo, int timeout)
{
	int wRet = 0;
	uint32_t	dwResLen;
	uint8_t 	*pRes = (uint8_t *)walloc(MAX_FAN_NUMS*sizeof(FanInfo_T) + 10);
	
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
							NETFNLUN_IPMI_STORLEAD, CMD_GET_FAN_INFO,
							NULL,	0,
							(uint8_t*)pRes,  &dwResLen,
							timeout);
	if(( wRet != 0 ) || (pRes[0] != 0))
	{
		printf("Error LIBIPMI_HL_GetFanInfo\n");
		return -1;
	}

	memcpy((uint8_t*)pFanInfo, pRes+1, dwResLen-1);
	return 0;
}

int IPMC_GetFanInfo(IPMI20_UDS_SESSION_T *pUDSSession, uint8_t IpmbAddr, FanInfo_T* pFanInfo, int timeout)
{
	int wRet = 0;
	uint32_t	dwResLen;
	uint8_t 	Req[10] = {0};
	uint8_t		*Res = (uint8_t *)walloc(MAX_FAN_NUMS*sizeof(FanInfo_T) + 20);

	Req[0] = 0x40;	//Track | channel 0
	Req[1] = IpmbAddr;
	Req[2] = NETFNLUN_IPMI_STORLEAD;
	Req[3] = 0x100 - (Req[1] + Req[2])&0xff;	//checksum1
	Req[4] = 0x20;
	Req[5] = 0x10;
	Req[6] = CMD_GET_FAN_INFO;	
	Req[7] = 0x100 - (Req[4] + Req[5] + Req[6])&0xff;

	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession, 
											DEFAULT_NET_FN_LUN, CMD_SEND_MSG,
											Req, 8,
											Res, &dwResLen,
											timeout);
	if(( wRet != 0 ) || (Res[6] != 0))
	{
			printf("Error IPMC_GetFanInfo\n");
			return -1;
	}

	memcpy((uint8_t*)pFanInfo, &Res[7], dwResLen-8);	//remove header and chksum
	return 0;
}

/*
*@fn IPMICMD_AMIGetSELEntires
*@brief
*@param pSession - IPMI Session Handle
*@param pAMIGetSelEntriesReq - Pointer to the request of AMI Get SEL Entries command
*@param pAMIGetSelEntiresRes - Pointer to the response of AMI Get SEL Entries command
*@param timeout - Timeout Value
**/
uint16_t IPMICMD_AMIGetSELEntires(IPMI20_UDS_SESSION_T *pUDSSession,AMIGetSELEntriesReq_T *pAMIGetSelEntriesReq,
											   AMIGetSELEntriesRes_T *pAMIGetSelEntiresRes,int timeout)
{
	uint16_t wRet;
	uint32_t dwResLen;
	dwResLen = sizeof(AMIGetSELEntriesRes_T);
	
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,
						NETFNLUN_IPMI_STORLEAD, CMD_GET_SEL_ENTIRES,
						(uint8_t *)pAMIGetSelEntriesReq, sizeof(AMIGetSELEntriesReq_T),
						(uint8_t*)pAMIGetSelEntiresRes, &dwResLen,
						timeout);
	
	return (wRet);
}

uint16_t IPMC_AMIGetSELEntires(IPMI20_UDS_SESSION_T *pUDSSession,  uint8_t IpmbAddr, AMIGetSELEntriesReq_T *pAMIGetSelEntriesReq,
											   AMIGetSELEntriesRes_T *pAMIGetSelEntiresRes,int timeout)
{
	int wRet = 0;
	uint32_t	dwResLen;
	uint8_t 	Req[50] = {0};
	uint8_t		Res[50] = {0};

	//first do a SEL reservation
	Req[0] = 0x40;	//Track | channel 0
	Req[1] = IpmbAddr;
	Req[2] = NETFNLUN_IPMI_STORLEAD;
	Req[3] = 0x100 - (Req[1] + Req[2])&0xff;	//checksum1
	Req[4] = 0x20;
	Req[5] = 0x10;
	Req[6] = CMD_GET_SEL_ENTIRES;	
	Req[7] = pAMIGetSelEntriesReq->Noofentretrieved&0xff;
	Req[8] = (pAMIGetSelEntriesReq->Noofentretrieved>>8)&0xff;
	Req[9] = (pAMIGetSelEntriesReq->Noofentretrieved>>16)&0xff;
	Req[10] = (pAMIGetSelEntriesReq->Noofentretrieved>>24)&0xff;
	Req[11] = 0x100 - (Req[4] + Req[5] + Req[6] + Req[7] + Req[8] + Req[9] + Req[10])&0xff;

	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
							NETFNLUN_IPMI_APP, CMD_SEND_MSG,
							Req, 12,
							Res,  &dwResLen,
							timeout);

	if((wRet != 0) || (Res[6] != 0))
	{
		printf("get sel entires failed!\n");
		memset(pAMIGetSelEntiresRes, 0, sizeof(AMIGetSELEntriesRes_T));
		return -1;
	}

	memcpy(pAMIGetSelEntiresRes, &Res[6], sizeof(AMIGetSELEntriesRes_T));
	return (wRet);
}


/*
*@fn LIBIPMI_HL_AMIGetSELEntires
*@brief High Level command to retrieve the total SEL Entries
*@param pSession - IPMI Session Handle
*@param pSELEntriesBuffer - Pointer to hold the retrieved SEL Entries
*@param nNumSelEntries - Pointer which hold the no. of SEL Entries retrieved
*@param timeout - Timeout Value
*@return Returns LIBIPMI_E_SUCCESS on success
*@return Returns proper completion code on error
**/
uint16_t Storlead_AMIGetSELEntires(IPMI20_UDS_SESSION_T *pUDSSession, uint8_t IpmbAddr,
	SELEventRecordWithSensorName_T *pSELEntriesBuffer,uint32_t *nNumSelEntries,int timeout)
{
	AMIGetSELEntriesReq_T pAMIGetSelEntriesReq = {0};
	AMIGetSELEntriesRes_T *pAMIGetSelEntiresRes;
	SELEventRecordWithSensorName_T *CircSELEntries;
	uint8_t *SELEntries;
	uint16_t wRet = 0;
	int j=0;
	uint16_t i=0,recindex=0;
	uint16_t LastRecID = 0xFFFF,MaxSELEntries=0;
	uint32_t max_sel_len = MAX_SEL_RECORD*sizeof(SELRec_T) + sizeof(AMIGetSELEntriesRes_T) + 256;//margin
	
	SELEntries = (uint8_t *)walloc(max_sel_len);
	if(SELEntries == NULL)
	{
		printf("Memory allocation error in LIBIPMI_HL_AMIGetSELEntires \n");
		wRet = 0xFF;
		return wRet;
	}
	
	memset(SELEntries,0,max_sel_len);
	pAMIGetSelEntiresRes = (AMIGetSELEntriesRes_T *)SELEntries;
	
	do
	{
		if(IpmbAddr == 0x20)
		{
			wRet = IPMICMD_AMIGetSELEntires(pUDSSession,&pAMIGetSelEntriesReq,(AMIGetSELEntriesRes_T *)SELEntries,timeout);
		}
		else
		{
			wRet = IPMC_AMIGetSELEntires(pUDSSession, IpmbAddr, &pAMIGetSelEntriesReq,(AMIGetSELEntriesRes_T *)SELEntries,timeout);
		}
		if(wRet == LIBIPMI_E_SUCCESS)
		{
			for(i = 0; i < pAMIGetSelEntiresRes->Noofentries; i++)
			{
				memcpy((uint8_t *)&pSELEntriesBuffer[i+*nNumSelEntries].EventRecord,&(SELEntries[sizeof(AMIGetSELEntriesRes_T) + (i * sizeof(SELRec_T))]),
							   sizeof(SELRec_T));
			}
	
			if(pAMIGetSelEntriesReq.Noofentretrieved == 0x00)
			{
				LastRecID = pAMIGetSelEntiresRes->LastRecID;
			}
	
			if(pAMIGetSelEntiresRes->Status == FULL_SEL_ENTRIES)
			{
				*nNumSelEntries += pAMIGetSelEntiresRes->Noofentries;
				break;
			}
			else
			{
				*nNumSelEntries += pAMIGetSelEntiresRes->Noofentries;
				pAMIGetSelEntriesReq.Noofentretrieved = *nNumSelEntries;
				memset(SELEntries,0,max_sel_len);
				continue;
			}
		}
		else if((wRet & 0xFF) == LIBIPMI_E_SEL_CLEARED)
		{
			memset(SELEntries,0,max_sel_len);
			memset((uint8_t*)&pSELEntriesBuffer[0],0,sizeof(SELEventRecordWithSensorName_T) * *nNumSelEntries);
			*nNumSelEntries =  pAMIGetSelEntriesReq.Noofentretrieved = 0;
			continue;
		}
		else if((wRet & 0xFF)  == LIBIPMI_E_SEL_EMPTY)
		{
			/* Returning LIBIPMI_E_SUCCESS when sel repo is empty as
				 per WebUI expectations. Will be removed once changes are made in WebUI*/
			wRet = LIBIPMI_E_SUCCESS;
			return wRet;
		}
		else
		{
			break;
		}
	}while(1);
	
	wfree(SELEntries);
	
	if(wRet == LIBIPMI_E_SUCCESS)
	{
		if(LastRecID != 0xFFFF)
		{
			if(IpmbAddr == 0x20)
			{
				wRet = LIBIPMI_HL_GetMaxPossibleSELEntries(pUDSSession,&MaxSELEntries,timeout);
			}
			else
			{
				wRet = IPMC_GetMaxPossibleSELEntries(pUDSSession,IpmbAddr, &MaxSELEntries,timeout);
			}
			if(wRet == LIBIPMI_E_SUCCESS)
			{
				 if(LastRecID > MaxSELEntries)
				{
					for(i = 0; i < *nNumSelEntries; i++)
					{
						if(pSELEntriesBuffer[i].EventRecord.EvtRecord.hdr.ID == LastRecID)
						{
							recindex = i;
							break;
						}
					}
	
					/* Last Record is not found if reached till end of SEL Entries*/
					if(i == *nNumSelEntries)
					{
						wRet = 0xFF;
						return wRet;
					}
	
					/*SEL Records added lastely will be displayed first */
					CircSELEntries = (SELEventRecordWithSensorName_T *)walloc (sizeof(SELEventRecordWithSensorName_T) * (*nNumSelEntries));
					if(CircSELEntries != NULL)
					{
						memset(CircSELEntries,0,sizeof(SELEventRecordWithSensorName_T) * (*nNumSelEntries));
						j = recindex; i = 0;
						while(j >= 0)
						{
							memcpy((uint8_t *)&CircSELEntries[i],(uint8_t*)&pSELEntriesBuffer[j],sizeof(SELEventRecordWithSensorName_T));
							j--;i++;
						}
	
						for(j = recindex + 1,i = 1; j < *nNumSelEntries; j++,i++)
						{
							memcpy((uint8_t*)&CircSELEntries[j],(uint8_t*)&pSELEntriesBuffer[*nNumSelEntries - i ],sizeof(SELEventRecordWithSensorName_T));
						}
	
						for(i = 0,j=1;i< *nNumSelEntries; i++,j++)
						{
							memcpy((uint8_t*)&pSELEntriesBuffer[i],(uint8_t*)&CircSELEntries[*nNumSelEntries - j],sizeof(SELEventRecordWithSensorName_T));
						}
						wfree(CircSELEntries);
					}
				}
			}
		}
	}
	return (wRet);
}

uint16_t IPMICMD_ResetBMC(IPMI20_UDS_SESSION_T *pUDSSession, int timeout)
{
	uint16_t wRet;
	uint32_t dwResLen;
	uint8_t res;
	
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,
						NETFNLUN_IPMI_APP, CMD_COLD_RESET,
						NULL, 0,
						(uint8_t*)&res, &dwResLen,
						timeout);
	
	return (wRet);
}

uint16_t IPMC_ResetBMC(IPMI20_UDS_SESSION_T *pUDSSession, uint8_t IpmbAddr, int timeout)
{
	int wRet = 0;
	uint32_t	dwResLen;
	uint8_t 	Req[10] = {0};
	uint8_t		Res[10] = {0};

	Req[0] = 0x40;	//Track | channel 0
	Req[1] = IpmbAddr;
	Req[2] = NETFNLUN_IPMI_APP;
	Req[3] = 0x100 - (Req[1] + Req[2])&0xff;	//checksum1
	Req[4] = 0x20;
	Req[5] = 0x10;
	Req[6] = CMD_COLD_RESET;	
	Req[7] = 0x100 - (Req[4] + Req[5] + Req[6])&0xff;

	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
							NETFNLUN_IPMI_APP, CMD_SEND_MSG,
							Req, 8,
							Res,  &dwResLen,
							timeout);
	
	
	return (wRet);
}

uint16_t IPMICMD_SetLanInfo(IPMI20_UDS_SESSION_T *pUDSSession, uint8_t index, LanInfo_T *pLanInfo, int timeout)
{
	uint16_t wRet;
	uint32_t dwResLen;
	uint8_t res[10];
	uint8_t req[100];
	
	req[0] = index; 
	memcpy(&req[1], pLanInfo, sizeof(LanInfo_T));
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,
						NETFNLUN_IPMI_STORLEAD, CMD_SET_LAN_INFO,
						req, sizeof(LanInfo_T)+1,
						(uint8_t*)res, &dwResLen,
						timeout);
	if(res[0] != 0)
	{
		printf("Set lan Info error!\n");
		return -1;
	}
	
	return (wRet);
}

uint16_t IPMICMD_GetLanInfo(IPMI20_UDS_SESSION_T *pUDSSession, uint8_t index, LanInfo_T *pLanInfo, int timeout)
{
	uint16_t wRet;
	uint32_t dwResLen;
	uint8_t res[100];
	uint8_t req[10];
	
	req[0] = index; 
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,
						NETFNLUN_IPMI_STORLEAD, CMD_GET_LAN_INFO,
						req, 1,
						res, &dwResLen,
						timeout);
	if(res[0] != 0)
	{
		printf("Get lan info error!\n");
		return -1;
	}

	memcpy(pLanInfo, res+1, sizeof(LanInfo_T));
	return (wRet);
}

uint16_t IPMICMD_restoreFactorySettings(IPMI20_UDS_SESSION_T *pUDSSession, int timeout)
{
	uint16_t wRet;
	uint32_t dwResLen;
	uint8_t res;
	
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,
						NETFNLUN_IPMI_STORLEAD, CMD_RESTORE_FACTORY_SET,
						NULL, 0,
						(uint8_t*)&res, &dwResLen,
						timeout);
	
	return (wRet);
}

uint16_t IPMC_restoreFactorySettings(IPMI20_UDS_SESSION_T *pUDSSession, uint8_t IpmbAddr, int timeout)
{
	uint16_t    wRet = 0;
    uint8_t     Req[20] = {0};
    uint8_t     Res[10];
    uint32_t    dwResLen;

	Req[0] = 0x40;	//Track | channel 0
	Req[1] = IpmbAddr;
	Req[2] = NETFNLUN_IPMI_STORLEAD;
	Req[3] = 0x100 - (Req[1] + Req[2])&0xff;	//checksum1
	Req[4] = 0x20;
	Req[5] = 0x10;
	Req[6] = CMD_RESTORE_FACTORY_SET;	
	Req[7] = 0x100 - (Req[4] + Req[5] + Req[6])&0xff;

	//dwResLen = sizeof(GetDevIDRes_T);
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession, 
											DEFAULT_NET_FN_LUN, CMD_SEND_MSG,
											Req,8,
											Res, &dwResLen,
											timeout);

	return (wRet);
}

int LIBIPMI_IPMC_GetDeviceID(IPMI20_UDS_SESSION_T *pUDSSession, uint8_t IpmbAddr, GetDevIDRes_T *DevIDRes, int timeout)
{
	int wRet = 0;
	uint32_t	dwResLen;
	uint8_t 	Req[10] = {0};
	uint8_t		Res[100] = {0};

	Req[0] = 0x40;	//Track | channel 0
	Req[1] = IpmbAddr;
	Req[2] = NETFNLUN_IPMI_APP;
	Req[3] = 0x100 - (Req[1] + Req[2])&0xff;	//checksum1
	Req[4] = 0x20;
	Req[5] = 0x10;
	Req[6] = CMD_GET_DEV_ID;	
	Req[7] = 0x100 - (Req[4] + Req[5] + Req[6])&0xff;

	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
							NETFNLUN_IPMI_APP, CMD_SEND_MSG,
							Req, 8,
							Res,  &dwResLen,
							timeout);

	int i;
	printf("GetDeviceID Res %d: ", dwResLen);
	for(i=0;i<dwResLen;i++)
	{
		printf("%#x ", Res[i]);
	}
	printf("\n");

	memcpy(DevIDRes, &Res[6], sizeof(GetDevIDRes_T));
	if(( wRet != 0 ) || (Res[6] != 0))
	{
			printf("Error IPMC GetDeviceID\n");
			return -1;
	}
		
	return 0;
}