/*
* Brief:	Handle all chassis function in this file. 
			Such as: Fan control, update power_good status, update chassis health status.
* Author:	Jimbo_Zhang@outlook.com
* Date:		2019-9-18
*/
#include <stdio.h>
#include <stdint.h>
#include <sys/prctl.h>
#include <semaphore.h>
#include <pthread.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

#include "main.h"
#include "ChassisTimerTask.h"
#include "ChassisDevice.h"
#include "com_IPMI_Chassis.h"
#include "SensorMonitor.h"
#include "time.h"

#include "com_IPMI_App.h"


int gFd_ChassisPwrHndlrQue;

void *ChassisTimerTask(void* pArg)
{
	MsgPkt_T	MsgPkt;
	uint32_t	preChassisSeconds;
	uint32_t	preFanSeconds;
	uint32_t	preIdentifySeconds = 0;
	uint8_t		IdentifyTickCnt = 0;
	prctl(PR_SET_NAME,__FUNCTION__,0,0,0);

	printf("ChassisTimerTask Started... \n");

	//create 
    if(-1 != access(CHASSIS_PWR_HNDLR_Q, F_OK))
    {
        remove(CHASSIS_PWR_HNDLR_Q);
    }
    if(0 != mkfifo (CHASSIS_PWR_HNDLR_Q, 0777))
    {
        printf("%s: Create %s fifo failed! %s\n", __FUNCTION__, CHASSIS_PWR_HNDLR_Q, strerror(errno));
        return (void*)-1;
    }
    gFd_ChassisPwrHndlrQue = open (CHASSIS_PWR_HNDLR_Q, O_RDWR);
    if(-1 == gFd_ChassisPwrHndlrQue)
    {
        printf("%s: Open %s fifo failed! %s\n", __FUNCTION__, CHASSIS_PWR_HNDLR_Q, strerror(errno));
        return (void*)-1;
    }

	preChassisSeconds	=	g_BMCInfo.CurTimerSecond;
	preFanSeconds	=	g_BMCInfo.CurTimerSecond;
	while(1)
	{
		if(GetMsg(gFd_ChassisPwrHndlrQue, &MsgPkt,  0) == 0)
		{
			if(MsgPkt.Param == PARAM_CHASSIS)
			{
				//Chassis power control
				if((NET_FN(MsgPkt.NetFnLUN) == NETFN_CHASSIS) && (MsgPkt.Cmd == CMD_CHASSIS_CONTROL))
				{
					switch(MsgPkt.Data[0])
					{
						case CHASSIS_POWER_DOWN:
							PDK_PowerOffChassis();
							break;
						case CHASSIS_POWER_UP:
							PDK_PowerOnChassis();
							break;
						case CHASSIS_POWER_CYCLE:
							PDK_PowerCycleChassis();
							break;
						case CHASSIS_HARD_RESET:
							PDK_ResetChassis();
							break;
						case CHASSIS_PULSE_DIAGNOSTIC_INTERRUPT:
							PDK_DiagInterruptChassis();
							break;
						case CHASSIS_SOFT_SHUTDOWN:
							PDK_SoftOffChassis();
							break;
						default:
							printf("Invalid power control cmd\r\n");
							break;
					}
				}
			}
			else if(MsgPkt.Param == PARAM_MC)
			{
				if(((MsgPkt.NetFnLUN>>2) == NETFN_APP) && ((MsgPkt.Cmd == CMD_COLD_RESET) || (MsgPkt.Cmd == CMD_WARM_RESET))) 
				{
					sleep(1);
					//NVIC_SystemReset();
					//TODO: reset stm32
				}
			}
		}
		
		//Chassis timer interval
		if((g_BMCInfo.CurTimerSecond != preChassisSeconds) 
			&&((g_BMCInfo.CurTimerSecond - preChassisSeconds) >= g_BMCInfo.IpmiConfig.ChassisTimerInterval))
		{
			//log("Chassis interval\r\n");
			preChassisSeconds	=	g_BMCInfo.CurTimerSecond;
			//TODO:
			g_BMCInfo.PowerGoodFlag = 1;
			g_BMCInfo.IpmiConfig.ChassisPowerState.PowerState	=	g_BMCInfo.PowerGoodFlag;
		}
		
		//Fan control
		if((g_BMCInfo.CurTimerSecond != preFanSeconds)
			&& (g_BMCInfo.CurTimerSecond % g_BMCInfo.IpmiConfig.FanControlInterval) == 0)
		{
			preFanSeconds	=	g_BMCInfo.CurTimerSecond;
			PDK_FanControl();
		}
		
		//Chassis Identify
		if(g_BMCInfo.ChassisIdentify == TRUE)
		{
			if(IdentifyTickCnt == 5)	//0.5s
			{
				IdentifyTickCnt++;
				printf("-> Turn on led!\r\n");
			}
			else if(IdentifyTickCnt == 10)
			{
				IdentifyTickCnt	=	0;
				printf("-> Turn off led!\r\n");
			}
			else
			{
				IdentifyTickCnt++;
			}
			
			//Identify finished
			if(((g_BMCInfo.CurTimerSecond - preIdentifySeconds) >= g_BMCInfo.ChassisIdentifyTimeout) 
				&& (g_BMCInfo.ChassisIdentifyForce != 1))
			{
				g_BMCInfo.ChassisIdentify	=	FALSE;
			}
		}
		else
		{
			preIdentifySeconds	=	g_BMCInfo.CurTimerSecond;
			IdentifyTickCnt	=	0;
		}
		
		sleep(1);
	}
}



