/*****************************************************************
******************************************************************
***                                                            ***
***        (C)Copyright 2008, American Megatrends Inc.         ***
***                                                            ***
***                    All Rights Reserved                     ***
***                                                            ***
***       5555 Oakbrook Parkway, Norcross, GA 30093, USA       ***
***                                                            ***
***                     Phone 770.246.8600                     ***
***                                                            ***
******************************************************************
******************************************************************
******************************************************************
* 
* Filename: libipmi_Chassis.c
*
* Descriptions: Chassis Control Subfunctions Implementation.
*   For documentation see file libipmi_ChassisDevice.h
*
* Author: Chennakesava Rao Arnoori
*
******************************************************************/
#include "libipmi_session.h"
#include "libipmi_errorcodes.h"
#include "libipmi_ChassisDevice.h"

#include "string.h"


/**
   \breif	Internel function to execute the raw IPMI Command
   @param	pSession		[in]Session handle
   @param	timeout			[in]timeout value in seconds.

   @retval Returns LIBIPMI_STATUS_SUCCESS on success and error codes on failure
*/
uint16_t IPMICMD_ChassisControl( IPMI20_UDS_SESSION_T *pUDSSession, int timeout, char cmd)
{

    uint32_t		dwResLen;
    uint16_t		wRet;
    ChassisControlReq_T ChassisReq;
    ChassisControlRes_T ChassisRes;
    
    ChassisReq.ChassisControl = cmd; 
    dwResLen = sizeof ( ChassisControlRes_T);


    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
					    NETFNLUN_IPMI_CHASSIS, CMD_CHASSIS_CONTROL,
					    (uint8_t *)&ChassisReq,sizeof(ChassisControlReq_T),
					    (uint8_t*)&ChassisRes, &dwResLen,
					    timeout);
    return wRet;
}


uint16_t IPMICMD_GetSystemBootOptions(IPMI20_UDS_SESSION_T *pUDSSession, GetBootOptionsReq_T* pReqGetBootOptions,
							 GetBootOptionsRes_T* pResGetBootOptions,int reslen,int timeout)
{
	uint16_t wRet;
	uint32_t dwResLen;

	dwResLen = reslen;
	
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
											NETFNLUN_IPMI_CHASSIS, CMD_GET_SYSTEM_BOOT_OPTIONS,
											(uint8_t*)pReqGetBootOptions, sizeof(GetBootOptionsReq_T),
											(uint8_t *)pResGetBootOptions, &dwResLen,
											timeout);
	return wRet;
	
}


uint16_t IPMICMD_SetSystemBootOptions(IPMI20_UDS_SESSION_T *pUDSSession, SetBootOptionsReq_T* pReqSetBootOptions,
							 SetBootOptionsRes_T* pResSetBootOptions,int reqlen,int timeout)
{
	uint16_t wRet;
	uint32_t dwResLen;
	SetBootOptionsReq_T local_ReqSetBootOptions;
	SetBootOptionsRes_T local_ResSetBootOptions;



	
	local_ReqSetBootOptions.ParamValidCumParam = 1; //for set in progress
	local_ReqSetBootOptions.BootParam.SetInProgress = 1;
	dwResLen = sizeof(SetBootOptionsRes_T);
	//first do a set in progress
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
											NETFNLUN_IPMI_CHASSIS, CMD_SET_SYSTEM_BOOT_OPTIONS,
											(uint8_t*)&local_ReqSetBootOptions, 2,
											(uint8_t *)&local_ResSetBootOptions, &dwResLen,
											timeout);

	if(wRet != 0)
	{
		printf("Error while doing set in progress first before doing SetSystemBootOptions\n");
		return wRet;
	}


	dwResLen = sizeof(SetBootOptionsRes_T);
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
											NETFNLUN_IPMI_CHASSIS, CMD_SET_SYSTEM_BOOT_OPTIONS,
											(uint8_t*)pReqSetBootOptions, reqlen,
											(uint8_t *)pResSetBootOptions, &dwResLen,
											timeout);
	if(wRet != 0)
	{
		printf("error doing actual set system boot options\n");
		return wRet;
	}

	//clear the set in progress
	local_ReqSetBootOptions.ParamValidCumParam = 1; //for set in progress
	local_ReqSetBootOptions.BootParam.SetInProgress = 0;
	dwResLen = sizeof(SetBootOptionsRes_T);
	//first do a set in progress
	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
										NETFNLUN_IPMI_CHASSIS, CMD_SET_SYSTEM_BOOT_OPTIONS,
										(uint8_t*)&local_ReqSetBootOptions, 2,
										(uint8_t *)&local_ResSetBootOptions, &dwResLen,
										timeout);

	if(wRet != 0)
	{
		printf("Error while doing set in progress first before doing SetSystemBootOptions\n");
		return wRet;
	}

	return wRet;
	
}



uint16_t IPMICMD_ChassisIdentify(IPMI20_UDS_SESSION_T *pUDSSession,int timeout,ChassisIdentifyReq_T* ChassisIdReq)
{
	 uint32_t		dwResLen;
    	 uint16_t		wRet;
	 ChassisIdentifyRes_T ChassisIdRes = {0};
	 
	 dwResLen = sizeof (ChassisIdentifyRes_T);
	 
	 wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
					    NETFNLUN_IPMI_CHASSIS, CMD_CHASSIS_IDENTIFY,
					    (uint8_t *)ChassisIdReq,sizeof(ChassisIdentifyReq_T),
					    (uint8_t*)&ChassisIdRes, &dwResLen,
					    timeout);
					    
	return wRet;
}


// uint16_t LIBIPMI_HL_PowerOff( IPMI20_UDS_SESSION_T *pUDSSession, int timeout )
// {
//     uint16_t	wRet;

//     wRet = IPMICMD_ChassisControl( pUDSSession, timeout, CHASSIS_POWEROFF);

//     if (wRet == LIBIPMI_E_SUCCESS){
// 	TDBG("Succefully executed powerOFF  command.\n");
//     }else
// 	TDBG("Error: PowerOFF Command Failed.\n");
	
//     return wRet;
// }

// uint16_t LIBIPMI_HL_PowerUp( IPMI20_UDS_SESSION_T *pUDSSession, int timeout )
// {
//     uint16_t	wRet;

//     wRet = IPMICMD_ChassisControl( pUDSSession, timeout, CHASSIS_POWERUP);

//     if (wRet == LIBIPMI_E_SUCCESS){
// 	TDBG("Succefully executed powerUP the command.\n");
//     }else
// 	TDBG("Error: PowerUp Command Failed.\n");
	
//     return wRet;
// }

// uint16_t LIBIPMI_HL_PowerCycle( IPMI20_UDS_SESSION_T *pUDSSession, int timeout )
// {
//     uint16_t	wRet;

//     wRet = IPMICMD_ChassisControl( pUDSSession, timeout, CHASSIS_POWERCYCLE);

//     if (wRet == LIBIPMI_E_SUCCESS){
// 	TDBG("Succefully executed powerCycle the command.\n");
//     }else
// 	TDBG("Error: PowerCycle Command Failed.\n");
	
//     return wRet;
// }

// uint16_t LIBIPMI_HL_HardReset( IPMI20_UDS_SESSION_T *pUDSSession, int timeout )
// {	//TODO: jimbo control rst1~10 pin
//     uint16_t	wRet;

//     wRet = IPMICMD_ChassisControl( pUDSSession, timeout, CHASSIS_HARDRESET);

//     if (wRet == LIBIPMI_E_SUCCESS){
// 	TDBG("Succefully executed HardReset the command.\n");
//     }else
// 	TDBG("Error: HardReset Command Failed.\n");
	
//     return wRet;
// }

// uint16_t LIBIPMI_HL_DiagInt( IPMI20_UDS_SESSION_T *pUDSSession, int timeout )
// {
//     uint16_t	wRet;

//     wRet = IPMICMD_ChassisControl( pUDSSession, timeout, CHASSIS_DIAGINT);

//     if (wRet == LIBIPMI_E_SUCCESS){
// 	TDBG("Succefully executed DiagInt command.\n");
//     }else
// 	TDBG("Error: DiagInt Command Failed.\n");
	
//     return wRet;
// }

// uint16_t LIBIPMI_HL_SoftOff( IPMI20_UDS_SESSION_T *pUDSSession, int timeout )
// {
//     uint16_t	wRet;

//     wRet = IPMICMD_ChassisControl( pUDSSession, timeout, CHASSIS_SOFTOFF);

//     if (wRet == LIBIPMI_E_SUCCESS){
// 	TDBG("Succefully executed SoftOff command.\n");
//     }else
// 	TDBG("Error: SoftOff Command Failed.\n");
	
//     return wRet;
// }

uint16_t	LIBIPMI_HL_GetChassisStatus( IPMI20_UDS_SESSION_T *pUDSSession, int timeout, chassis_status_T *status)
{

    uint32_t		dwResLen;
    uint16_t		wRet;
    uint8_t		ChassisStatusReq;
    GetChassisStatusRes_T ChassisStatusRes;
    uint8_t		powerState = -1;

    dwResLen = sizeof(GetChassisStatusRes_T);
    
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
					    NETFNLUN_IPMI_CHASSIS, CMD_GET_CHASSIS_STATUS,
					    (uint8_t *)&ChassisStatusReq, 0 ,
					    (uint8_t*)&ChassisStatusRes, &dwResLen,
					    timeout);
    
    powerState = ChassisStatusRes.ChassisPowerState.PowerState ;
    
//    TINFO("PowerState is %d \n", powerState);
    
    status->power_state = powerState & 0x01;

    status->last_power_event = ChassisStatusRes.ChassisPowerState.LastPowerEvent;


    if(ChassisStatusRes.ChassisPowerState.MiscChassisState & CHASSIS_IDENTITY_STATE_INFO_SUPPORTED)
    {
	status->chassis_indetify_supported = 1;
    }
    else
    {
	status->chassis_indetify_supported = 0;
    }


    if(ChassisStatusRes.ChassisPowerState.MiscChassisState & CHASSIS_IDENTITY_INDEFINITE_ON)
    {
	status->chassis_identify_state = CHASSIS_ID_INDEFINITE_ON;
    }
    else if(ChassisStatusRes.ChassisPowerState.MiscChassisState & CHASSIS_IDENTITY_TIMED_ON)
    {
        status->chassis_identify_state = CHASSIS_ID_TIMED_ON;
    }
    else
    {
	status->chassis_identify_state = CHASSIS_ID_OFF;
    }
    
    return wRet;
}


//will turn chassis identify on or off
//BlinkTime - Set to TURN_OFF for turning off indefinitely
//	      Set to Interval in secs for chassis identify to be on for that much time.
// 	      for indefinite interval set ForceOn to 1.
// ForceOn - overrides BlinkTime settings if set to 1.Set to 0 if controlling by interval
uint16_t LIBIPMI_HL_ChassisIdentify(IPMI20_UDS_SESSION_T *pUDSSession, int timeout,uint8_t BlinkTimeSecs,FORCE_CHASSIS_ID ForceOn)
{
	uint16_t wRet;
	
	ChassisIdentifyReq_T ChassisIdReq = {0};
	
	//set interval to blinktimesecs. If caller set it to 0 so be it.
	//The caller should always give a time to this function . He can Use SPEC_DEFAULT to get default timeout behavior.
	ChassisIdReq.IdentifyInterval = BlinkTimeSecs;
	ChassisIdReq.ForceIdentify = ForceOn;
	
	printf("id interval and  force in libipmi are %d %d \n",ChassisIdReq.IdentifyInterval,ChassisIdReq.ForceIdentify);
	
	wRet = IPMICMD_ChassisIdentify(pUDSSession,timeout,&ChassisIdReq);
	
	if(wRet == LIBIPMI_E_SUCCESS)
	{
		printf("Chassis identify command success\n");
	}
	else
	{	
		printf("Chassis Identify failed for the following params : %d %d",BlinkTimeSecs,ForceOn);
	}
	
	return wRet;
}


uint16_t	LIBIPMI_HL_GetSystemBootOptions_BootFlags( IPMI20_UDS_SESSION_T *pUDSSession, BootFlags_T* pBootFlags,int timeout)
{
	uint16_t wRet;
	GetBootOptionsReq_T ReqGetBootOptions;
	GetBootOptionsRes_T ResGetBootOptions;
	int reslen;

	//form the request
	ReqGetBootOptions.ParamSel = 5;
	ReqGetBootOptions.BlockSel = 0;
	ReqGetBootOptions.SetSel = 0;

	//calculate the response length
	//we want the common response header + the sizeof bootflags
	reslen = 3 + sizeof(BootFlags_T);


	wRet = IPMICMD_GetSystemBootOptions(pUDSSession,&ReqGetBootOptions,&ResGetBootOptions,reslen,timeout);

	if(wRet != 0)
	{
		printf("Error getting system boot options when trying to get boot flags error code  is %x\n",wRet);
		return wRet;
	}

	//check the response
	if(ResGetBootOptions.ParameterValid & 0x80) 
	{
		printf("Got a parameter invlaid/locked error when trying to get Boot flags\n");
    }

	//we have the boot flags
	memcpy(pBootFlags,&ResGetBootOptions.BootParams.BootFlags,sizeof(BootFlags_T));

	return 0;
}


uint16_t	LIBIPMI_HL_SetSystemBootOptions_BootFlags( IPMI20_UDS_SESSION_T *pUDSSession, BootFlags_T* pBootFlags,int timeout)
{
	uint16_t wRet;
	SetBootOptionsReq_T ReqSetBootOptions;
	SetBootOptionsRes_T ResSetBootOptions;
	int reqlen;


    
	//form the request
	ReqSetBootOptions.ParamValidCumParam = 5; //for bootflags
	memcpy((uint8_t*)&(ReqSetBootOptions.BootParam.BootFlags),pBootFlags,sizeof(BootFlags_T));
	
	
	
	//we want the common response header + the sizeof bootflags
	reqlen = 1 + sizeof(BootFlags_T);




	wRet = IPMICMD_SetSystemBootOptions(pUDSSession,&ReqSetBootOptions,&ResSetBootOptions,reqlen,timeout);

	if(wRet != 0)
	{
		printf("Error setting system boot options when trying to set boot flags error code  is %x\n",wRet);
		return wRet;
	}


	return 0;
}
