/*
* @filename PFM_CPUUsage.c
* @brief Platform Function Module:CPU使用率获取
* @details
* 
* @author GT-BU
* @date 2022.08.22
* @version V1.0
* @copyright TCT
* @par 修改日志
* <table>
* <tr><th>Date        <th>Version  <th>Author     <th>Description
* <tr><td>2022.08.22  <td>V1.0     <td>GT-BU      <td>创建初始版本
* </table>
*/
#include "PFM_CPUUsage.h"
#include "PFM_Log.h"
#include "CM_Time.h"
#include "CM_Memory.h"
#include "DFM_Time.h"
#include "CFM_Net.h"
#ifdef WIN32
static CM_INT32 pipe_fd[2];

CM_FLOAT32  g_CpuTotal_Usage = 0.0;
static CM_FLOAT32  g_Cpu_Usage[6] = {0.0};
static ENUM_CM_RETURN CM_String_Split(IN CM_CHAR *src , IN const CM_CHAR *separator , INOUT CM_CHAR **dest , INOUT CM_INT32 *num);

ENUM_CM_RETURN PFM_CPUUsage(void)
{
	
}

/**
* @brief CPU使用率获取线程（子进程创建）
* @param arg 指向STRU_CFM_RECV_CTRL的指针
* @details
*/
CM_THREAD_FUNC_T t_CpuUsage_GetC(IN CM_Thread_Arg_Struct_T* arg)
{
    return 0;
}

/**
* @brief CPU使用率获取线程（父进程创建）
* @param arg 指向STRU_CFM_RECV_CTRL的指针
* @details
*/
CM_THREAD_FUNC_T t_CpuUsage_GetP(IN CM_Thread_Arg_Struct_T* arg)
{
    return 0;
}

/**
* @breif CPU使用率获取初始化
* @param p_CpuUsageParaCPU使用率buf
* @details
*/
void PFM_CpuUsage_Init(CM_UINT8 CpuUsageFlag)
{

}

/**
* @brief 获取CPU合计使用率
* @return CPU合计使用率，范围为0到100
*/
CM_FLOAT32 PFM_GetTotalCpuUsagePara(void)
{

}

/**
* @brief 获取指定CPU使用率
* @param 获取指定CPU使用率,值的范围为0到5
* @return 指定CPU使用率，范围为0到100
*/
CM_FLOAT32 PFM_GetAppointCpuUsagePara(CM_UINT8 CpuIndex)
{

}

/**
* @brief 字符串按指定分隔符分割子串
* @param src 源字符串的首地址(buf的地址)
* @param separator 指定的分割字符
* @param dest 接收子字符串的数组
* @param num 分割后子字符串的个数
* @return 连接结果
* - ENUM_CM_TRUE 成功
* - ENUM_CM_FALSE 失败
*/
static ENUM_CM_RETURN CM_String_Split(IN CM_CHAR *src , IN const CM_CHAR *separator , INOUT CM_CHAR **dest , INOUT CM_INT32 *num)
{

}

/**
* @brief 获取CPU使用率（子进程调用）
* @return
*/
ENUM_CM_RETURN PFM_CPUUsageC(void)
{

}
/**
* @brief 获取CPU使用率（父进程调用）
* @return
*/
ENUM_CM_RETURN PFM_CPUUsageP(void)
{

}
#else
typedef struct
{
	CM_UINT16 	CpuTotalMem;
	CM_UINT16 	CpuAvailMem;
	CM_FLOAT32  CpuTotal_Usage;
	CM_FLOAT32  Cpu_Usage[6];
}STRU_CPU_USAGE_T;
/*cpu使用率结构体*/
static STRU_CPU_USAGE_T s_CpuUsage;

static ENUM_CM_RETURN CM_String_Split(IN CM_CHAR *src , IN const CM_CHAR *separator , INOUT CM_CHAR **dest , INOUT CM_INT32 *num);
/**
* @brief CPU使用率获取线程（子进程创建）
* @param arg 指向STRU_CFM_RECV_CTRL的指针
* @details
*/
CM_THREAD_FUNC_T t_CpuUsage_GetC(IN CM_Thread_Arg_Struct_T* arg)
{
#ifdef QNX
    void* pmask = NULL;
    /*- 本线程锁定在 A53 core 1 */
    pmask = (void*)(0x01U | 0x02U);
    (void)ThreadCtl(_NTO_TCTL_RUNMASK, pmask);
#endif
	ENUM_CM_RETURN rt = ENUM_CM_FALSE; /* 函数返回值 */
	while(1)
	{		
		rt = PFM_CPUUsageC();
		if (ENUM_CM_FALSE == rt)
		{
			MSCP_LOG_MSG("Warning:PFM_CPUUsageC error!!!\n");
		}
		else
		{
			/* 无处理 */
		}

		/* 休眠1秒 */
		CM_Sleep(1000u);
	}
	return arg;
}

/**
* @breif CPU使用率获取初始化
* @param p_CpuUsageParaCPU使用率buf
* @details
*/
void PFM_CpuUsage_Init(void)
{
	CM_BOOL threadrtn = CM_FALSE;
	if (0x55u == g_PFM_Cfg.M_CpuUsageGet_Enable)
	{	
		/*- 子进程，创建线程获取CPU使用率，并将数据通过管道发送给父进程 */
		threadrtn=CM_Thread_Create((CM_THREAD_T*)NULL, (CM_THREAD_FUNC_T)t_CpuUsage_GetC, "CpuUsage_C", 0, CM_TASK_PRIORITY_91, NULL);
		CM_RE_ASSERT(CM_TRUE == threadrtn, CPU_USAGE_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_1);
	}
	else
	{	
		/*应用没注册，不使用该功能*/
	}
}

/**
* @brief 获取CPU合计使用率
* @return CPU合计使用率，范围为0到100
*/
CM_FLOAT32 PFM_GetTotalCpuUsagePara(void)
{
	return s_CpuUsage.CpuTotal_Usage;
}

/**
* @brief 获取指定CPU使用率
* @param 获取指定CPU使用率,值的范围为0到5
* @return 指定CPU使用率，范围为0到100
*/
CM_FLOAT32 PFM_GetAppointCpuUsagePara(CM_UINT8 CpuIndex)
{
	if (5u >= CpuIndex)
	{
		/* 无处理 */
	}
	else
	{
		CM_RE_ASSERT(0, CPU_USAGE_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_1);
	}
	return s_CpuUsage.Cpu_Usage[CpuIndex];
}
/**
* @brief CPU全部使用率暗文日志发送
* @return 无
*/
void PFM_GetAllCpuUsageInterface(void)
{
	CM_UINT8 Cpu_UsageMem[11] = {0};
	Cpu_UsageMem[0] = (CM_UINT8)s_CpuUsage.CpuTotal_Usage;
	/* 循环读取6行,每行内容为CPU从0到5的cpu空闲使用率 */
	for(int i=0;i<6;i++)
	{
		Cpu_UsageMem[i+1] = (CM_UINT8)s_CpuUsage.Cpu_Usage[i];
	}
	CM_ShortToChar(s_CpuUsage.CpuTotalMem,&Cpu_UsageMem[7]);
	CM_ShortToChar(s_CpuUsage.CpuAvailMem,&Cpu_UsageMem[9]);
	MSCP_LOG_MSG("cpud usage Total:%d,C1:%d,C2:%d,C3:%d,C4:%d,C5:%d,C6:%d,MT:%dM,AM:%dM\n",
			Cpu_UsageMem[0],Cpu_UsageMem[1],Cpu_UsageMem[2],Cpu_UsageMem[3],Cpu_UsageMem[4],Cpu_UsageMem[5],Cpu_UsageMem[6],s_CpuUsage.CpuTotalMem,s_CpuUsage.CpuAvailMem);
	(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_CPUMEMUSAGE, 11U, Cpu_UsageMem);
}
/**
* @brief 字符串按指定分隔符分割子串
* @param src 源字符串的首地址(buf的地址)
* @param separator 指定的分割字符
* @param dest 接收子字符串的数组
* @param num 分割后子字符串的个数
* @return 连接结果
* - ENUM_CM_TRUE 成功
* - ENUM_CM_FALSE 失败
*/
static ENUM_CM_RETURN CM_String_Split(IN CM_CHAR *src , IN const CM_CHAR *separator , INOUT CM_CHAR **dest , INOUT CM_INT32 *num)
{

	ENUM_CM_RETURN rt = ENUM_CM_FALSE; /* 函数返回值 */
	CM_CHAR *pNext;
    CM_INT32 count = 0;
	
    if ((src == NULL) || (strlen(src) == 0U) || (separator == NULL) || (strlen(separator) == 0U)|| (dest == NULL) || (num == NULL))
    {
    	/*- 参数不合法 */
		rt = ENUM_CM_FALSE;
	}
	else
	{
	    pNext = (CM_CHAR *)strtok(src,separator); /*必须使用(char *)进行强制类型转换(虽然不写有的编译器中不会出现指针错误)*/
	    while(pNext != NULL)
		{
	         *dest++ = pNext;
	         ++count;
	         pNext = (CM_CHAR *)strtok(NULL,separator);  /*必须使用(char *)进行强制类型转换*/
	    }
	    *num = count;
		rt = ENUM_CM_TRUE;
	}
	/*- 返回结果 */
    return rt;
}
/**
* @brief 获取CPU使用率（子进程调用）
* @return 
*/
ENUM_CM_RETURN PFM_CPUUsageC(void)
{
	FILE *fp=NULL;
	CM_CHAR StrLine[LINE_LEN] = {0}; /*每行最大读取的字符数*/
	CM_CHAR *unPackbuf[FIELD_LEN] = {0}; /*存放分割后的子字符串*/
	CM_INT32 num = 0;
	CM_INT32 ret = -1; /*函数返回值*/
	CM_FLOAT32 percent=(CM_FLOAT32)0.0;
	CM_FLOAT32 percenttmp=(CM_FLOAT32)0.0;
	CM_FLOAT32 percentfull=(CM_FLOAT32)100.0;
	CM_UINT16 	TotalMem = 0u;
	CM_UINT16 	AvailMem = 0u;
	ENUM_CM_RETURN rt = ENUM_CM_FALSE; /* 函数返回值 */
	
	/* 通过popen函数，管道方式执行命令 */
	fp = popen("top -b -i 1","r");
	if(NULL != fp)
	{
		/* 读取一行,使文件读指针跳到第二行CPU信息行 */
		(void)fgets(StrLine,LINE_LEN,fp);
		/* 读取一行,该行内容为CPU总计 */
	 	(void)CM_Memset(StrLine,0x00,sizeof(StrLine),sizeof(StrLine));
	 	(void)fgets(StrLine,LINE_LEN,fp);
		/*将该行内容按照空格拆分，获取各字段值*/
		rt = CM_String_Split(&StrLine[0], " ", unPackbuf, &num);
		if(ENUM_CM_TRUE == rt)
		{
			/*第三个字段为用户总计使用率，去掉该字段的百分号*/
			(void)sscanf(unPackbuf[2],"%f%%",&percenttmp);
			/*第五个字段为内核总计使用率，去掉该字段的百分号*/
			(void)sscanf(unPackbuf[4],"%f%%",&percent);
			percent += percenttmp;
			s_CpuUsage.CpuTotal_Usage = percent;
		}
		else
		{
			/*无处理*/
		}
		/* 循环读取6行,每行内容为CPU从0到5的cpu空闲使用率 */
		for(int i=0;i<6;i++)
		{
			/* 读取一行,该行内容为CPU空闲使用率 */
			(void)CM_Memset(StrLine,0x00,sizeof(StrLine),sizeof(StrLine));
			(void)fgets(StrLine,LINE_LEN,fp);

			/*将该行内容按照空格拆分，获取各字段值*/
			rt = CM_String_Split(&StrLine[0], " ", unPackbuf, &num);
			if(ENUM_CM_TRUE == rt)
			{
				/*第四个字段为cpu空闲使用率，去掉该字段的百分号*/
				(void)sscanf(unPackbuf[3],"%f%%",&percent);
				s_CpuUsage.Cpu_Usage[i] = percentfull-percent;
			}
			else
			{
				rt = ENUM_CM_FALSE;
			}
		}
		/* 读取一行,该行内容为内存使用率 */
		(void)CM_Memset(StrLine,0x00,sizeof(StrLine),sizeof(StrLine));
		(void)fgets(StrLine,LINE_LEN,fp);
		/*将该行内容按照空格拆分，获取各字段值*/
		rt = CM_String_Split(&StrLine[0], " ", unPackbuf, &num);
		if(ENUM_CM_TRUE == rt)
		{
			(void)sscanf(unPackbuf[1],"%d%[A-Z]",&TotalMem);
			(void)sscanf(unPackbuf[3],"%d%[A-Z]",&AvailMem);
			/*赋值*/
			s_CpuUsage.CpuTotalMem = TotalMem;
			s_CpuUsage.CpuAvailMem = AvailMem;
		}
		else
		{
			rt = ENUM_CM_FALSE;
		}		
		
		/* 关闭文件指针 */
		ret = pclose(fp);
		if(-1 == ret)
	    {
	        perror("pclose failed");
	        rt = ENUM_CM_FALSE;
	    }
	    else
	    {
			
			rt = ENUM_CM_TRUE;
	    }
	}
	else
	{
		perror("popen call failed");
		MSCP_LOG_MSG("popen call failed!!\n");
		MSCP_LOG_MSG("popen errno=%d,%s\n",errno,strerror(errno));
		rt = ENUM_CM_FALSE;
	}
	return rt;	
}
#endif
