/**
* @filename PFM_SelfCheck.c
* @brief Platform Function Module:自检
* @details
* @author GT-BU
* @date 2021.09.24
* @version V1.0
* @copyright TCT
* @par 修改日志
* <table>
* <tr><th>Date        <th>Version  <th>Author     <th>Description
* <tr><td>2021.09.24  <td>V1.0     <td>GT-BU      <td>创建初始版本
* </table>
*/
#include "PFM_SelfCheck.h"
#include "DFM_Time.h"
#include "DFM_DRV.h"
#include "CM_IniFile.h"
#include "CM_MD5.h"
#include "CM_Memory.h"
#include "PFM_Cfg.h"
#include "PFM_Log.h"
#include "CM_Com.h"
#include "CM_CRC32.h"
#include "CM_Convert.h"
#include "CM_Time.h"
#include "CFM_Net.h"
/*定义温度最低值,此宏应该放在文件配置*/
#define DFM_LOW_TMP ((CM_FLOAT32)(-40))
/*定义温度最大值，此宏应该放在文件配置*/
#define DFM_MAX_TMP ((CM_FLOAT32)(85))


/*定义读取文件的buf大小*/
#define FILEB_MAX_LEN (1024*1024*100u) /*100M*/

/*定义分块自检长度*/
#define BLOCK_LEN (1024U)
/* 文件管理结构体 */
typedef struct
{
	CM_CHAR fileName[1024];/*- 文件名*/
	CM_INT64 fileSize;/*- 文件大小*/
    MD5Context_T md5Str;/*- 周期分片校验的MD5结构体*/
    CM_UINT8  md5[16];/*- 存储初始比较时的校验码*/
    CM_UINT32 blocklen;/*- 分块校验数据长度*/
    CM_UINT32 blockcnt;/*- 分块数*/
    CM_UINT32 offset;/*- 当前待校验块索引*/
    FILE *file;/*- 文件指针*/
    CM_UINT8 initFalg ;/*初始化标志位*/
}STRU_FILE_CTRL_T;

static struct sigaction act;
/* 记录步骤 */
extern CM_INT32 g_PFM_Check;
static CM_INT32 s_PFM_AppCheck;

/*APP自检管理结构体*/
static STRU_FILE_CTRL_T s_FileCtrl_APP;
/*读取文件buf 100M*/
CM_UINT8 fileBuf[1024*1024*100];

/* 信号抓捕函数 */
static void signal_handler(void);
/*文件自检初始化*/
static void PFM_FileCheckInit(IN STRU_FILE_CTRL_T *pManage, IN CM_CHAR *pFileName, IN CM_UINT8 *pMd5, IN CM_UINT16 blockLen);
/*温度自检*/
static void PFM_BoardTmpCheck(void);

/**
* @brief 平台自检文件初始化
*/
void PFM_FileInit(void)
{
	PFM_FileCheckInit(&s_FileCtrl_APP, g_PFM_Cfg.APP_NAME, g_PFM_Cfg.APP_MD5 ,BLOCK_LEN);
}
/**
* @brief 指定文件初始化接口
* @param pManage 自检管理结构体
* @param pFileName 文件名
* @param pMd5 文件MD5值
* @param blockLen 分块的大小
* @details
*/
static void PFM_FileCheckInit(IN STRU_FILE_CTRL_T *pManage, IN CM_CHAR *pFileName, IN CM_UINT8 *pMd5, IN CM_UINT16 blockLen)
{
	CM_INT32 rtn = 0;
	CM_UINT8 md5Buf[16u] = {0u};
	/*- 指针防空*/
	if((NULL != pManage)&&(NULL != pManage->md5)&&
	   (NULL != pManage->fileName)&&(NULL != pFileName)&&(NULL != pMd5))
	{
		/*- 初始化Md5管理结构体*/
		(void)CM_MD5_Init(&pManage->md5Str);
		/*- 拷贝文件名*/
		(void)strcpy(pManage->fileName,pFileName);
		/*- 记录原始文件MD5*/
		(void)CM_Memcpy(pManage->md5,16u, pMd5,16u);
		/*获取文件大小*/
		pManage->fileSize = CM_GetFileSize(pManage->fileName);
		CM_ASSERT(((CM_INT64)0 != pManage->fileSize) && (pManage->fileSize < (CM_INT64)FILEB_MAX_LEN), SELF_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_1);
		/*- 设置块大小*/
		pManage->blocklen = blockLen;
		/*- 计算分块数量*/
		pManage->blockcnt = CM_UNSIGNED_INT_EXP(((CM_UINT32)pManage->fileSize + blockLen - 1U)/blockLen);
		/*- 文件偏移量初始化*/
		pManage->offset = 0u;
		/*- 读取文件*/
		rtn = CM_ReadFile(pManage->fileName, 0u , pManage->fileSize, fileBuf);
		CM_ASSERT(rtn, SELF_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_2);
		/*- 计算文件MD5*/
		(void)CM_MD5_Calc(fileBuf, (CM_UINT32)pManage->fileSize, md5Buf);
		/*- 比较读取文件的md5和存储的md5是否相同*/
		rtn = CM_Memcmp(md5Buf,pManage->md5,16u);
		MSCP_LOG_MSG("file name %s \r\n",pManage->fileName);
		CM_ASSERT((CM_INT32)0 == rtn, SELF_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_3);
		/*- 初始化文件操作为NULL*/
		pManage->file = fopen(pManage->fileName, "r");
		CM_ASSERT(NULL != pManage->file, SELF_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_4);
		(void)fclose(pManage->file);
		/*- 将初始化设置为已经初始化*/
		pManage->initFalg = 1u;
	}
	else
	{
		/*- 无操作*/
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_WARNING, 4U, DARK_FAULT_CODE_MERGE(SELF_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_1));
	}
}

/**
* @brief 设置板卡温度范围
* @param MinTemperature 最低温度
* @param MinTemperature 最高温度
* @return 函数执行结果
* - 1 成功
* - 0 失败
*/
CM_UINT8 PFM_SetTemperature(CM_FLOAT32 MinTemperature , CM_FLOAT32 MaxTemperature)
{
	CM_UINT8 rt = 0u;
	
	if ((DFM_LOW_TMP < MinTemperature) && (DFM_MAX_TMP > MinTemperature) && \
		(DFM_LOW_TMP < MaxTemperature) && (DFM_MAX_TMP > MaxTemperature) && \
		(MinTemperature < MaxTemperature) &&(0u == gSetTempFlag))
	{
		gMinTemperature = MinTemperature;
		gMaxTemperature = MaxTemperature;
		gSetTempFlag++;
		rt = 1u;
		MSCP_LOG_MSG("SetTemperature sucessful!! MinTemperature = %.2f,MaxTemperature = %.2f\n",MinTemperature,MaxTemperature);
	}
	else
	{
		rt = 0u;
		MSCP_LOG_MSG("SetTemperature fail!! MinTemperature = %.2f,MaxTemperature = %.2f,gSetTempFlag = %u\n",MinTemperature,MaxTemperature,gSetTempFlag);
	}
	
	return rt;
}

/**
* @brief 板卡温度自检
*/
static void PFM_BoardTmpCheck(void)
{
	/*- 变量初始化 */
	CM_UINT8 state = 0xAAu;
	static CM_UINT8 s_err_cut = 0u;
	CM_FLOAT32 tmp = (CM_FLOAT32)0.0;
	CM_INT32 tmpsend = 0;
	CM_FLOAT64 iotmp = (CM_FLOAT64)0.0;
	/*- 读取主机板表面温度  */
	tmp = DFM_Get_Tmp112();
	tmpsend = tmp * 1000;
	MSCP_LOG_MSG("tmp %lf \r\n",tmp);
	MSCP_LOG_MSG("tmp %d \r\n",tmpsend);
	(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_TMP, 4u, &tmpsend);
	if(1u == gSetTempFlag)
	{
		if((tmp > gMinTemperature) && (tmp < gMaxTemperature))
		{
			s_err_cut = 0u;
			state = 0x55u;
			(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_DRVINIT, 1u, &state);
		}
		else
		{
			s_err_cut++;
			if(s_err_cut >= 3u)
			{
				(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_DRVINIT, 1u, &state);
				CM_ASSERT(0, SELF_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
			}
			else
			{
				MSCP_LOG_MSG("warning tmp1 %lf \r\n",tmp);
				(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_WARNING, 4U, DARK_FAULT_CODE_MERGE(SELF_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_1));
			}
		}
	}
	else
	{
		if((tmp > DFM_LOW_TMP) && (tmp < DFM_MAX_TMP))
		{
			s_err_cut = 0u;
			state = 0x55u;
			(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_DRVINIT, 1u, &state);
		}
		else
		{
			s_err_cut++;
			if(s_err_cut >= 3u)
			{
				(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_DRVINIT, 1u, &state);
				CM_ASSERT(0, SELF_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_4);
			}
			else
			{
				MSCP_LOG_MSG("warning tmp2 %lf \r\n",tmp);
				(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_WARNING, 4U, DARK_FAULT_CODE_MERGE(SELF_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_2));
			}
		}
	}
	/*- 读取io板表面温度 (io板卡tmp只做读取操作,不做自检操作,只有cpu1能读出来) */
	if(1u == PFM_CFG_GetCpuID())
	{
		iotmp = DFM_Get_Tmp117();
		MSCP_LOG_MSG("io tmp %lf \r\n",iotmp);
		tmpsend = iotmp * 1000;
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_IOTMP, (CM_UINT32)4u, &tmpsend);
	}
	else
	{
		/*- 无处理 */
	}

	MSCP_LOG_MSG("cpu tmp %d \r\n",DFM_Read_cputemp());
}
/**
* @brief 串口回环自检
*/
void PFM_UartComCheck(void)
{
	ENUM_CM_RETURN ret = ENUM_CM_FALSE;
	CM_UINT16 len = 0u;
	CM_UINT16 offset = 2u;
	CM_UINT8 SendBuf[20u] = {0u};
	CM_UINT32 crc = 0u;

	/*自检发送组包 2字节长度+1字节类型+1字节板卡ID+1字节CPUID+4字节CRC*/
	SendBuf[offset] = (CM_UINT8)ENUM_COM_SelfCheck;
	offset++;
	SendBuf[offset] = g_PFM_Cfg.BOARD_ID;
	offset++;
	SendBuf[offset] = g_PFM_Cfg.CPU_ID;
	offset++;
	CM_ShortToChar((offset - (CM_UINT16)2u),&SendBuf[0u]);
	crc = CM_Crc32(SendBuf,(CM_UINT32)offset);
	CM_LongToChar(crc,&SendBuf[offset]);
	len = offset + 4u;
#ifdef QNX
	/*串口数据发送*/
	ret = CM_Com_LocalDataSend(SendBuf,len);
	CM_NM_ASSERT(ENUM_CM_TRUE == ret, SELF_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_1);
#endif
}

/**
* @brief 板卡自检
*/
void PFM_BoardCheck(void)
{
	CM_INT32 ret;
	CM_INT32 channel_1_shunt;
	CM_INT32 channel_2_shunt;
	CM_INT32 channel_3_shunt;
	CM_FLOAT32 channel_1_bus;
	CM_FLOAT32 channel_2_bus;
	CM_FLOAT32 channel_3_bus;
	CM_INT32 send_channel_1_bus;
	CM_INT32 send_channel_2_bus;
	CM_INT32 send_channel_3_bus;
	CM_UINT8 rBuf[24];

	/*- 读取三个通道的电流电压 */
	ret = DFM_Read_ina3321(&channel_1_shunt, &channel_1_bus, &channel_2_shunt, &channel_2_bus, &channel_3_shunt, &channel_3_bus);
	if(0 == ret)
	{
		MSCP_LOG_MSG("%d, %f, %d, %f, %d, %f\n",channel_1_shunt,channel_1_bus,channel_2_shunt,channel_2_bus,channel_3_shunt,channel_3_bus);
		send_channel_1_bus = channel_1_bus * 1000;
		(void)CFM_DarkLog_Storage(DARK_LOG_DEC, TSCP_DARK_CHANNEL_1_SHUNT, 4u, &channel_1_shunt);
		(void)CFM_DarkLog_Storage(DARK_LOG_DEC, TSCP_DARK_CHANNEL_1_BUS, 4u, &send_channel_1_bus);
		send_channel_2_bus = channel_2_bus * 1000;
		(void)CFM_DarkLog_Storage(DARK_LOG_DEC, TSCP_DARK_CHANNEL_2_SHUNT, 4u, &channel_2_shunt);
		(void)CFM_DarkLog_Storage(DARK_LOG_DEC, TSCP_DARK_CHANNEL_2_BUS, 4u, &send_channel_2_bus);
		send_channel_3_bus = channel_3_bus * 1000;
		(void)CFM_DarkLog_Storage(DARK_LOG_DEC, TSCP_DARK_CHANNEL_3_SHUNT, 4u, &channel_3_shunt);
		(void)CFM_DarkLog_Storage(DARK_LOG_DEC, TSCP_DARK_CHANNEL_3_BUS, 4u, &send_channel_3_bus);
	}
	else
	{
		MSCP_LOG_MSG("Read ina3321 fail.\n");
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_WARNING, 4U, DARK_FAULT_CODE_MERGE(SELF_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_1));
	}
	/*- 读取eeprom信息 */
	ret = DFM_Read_eeprom(1, rBuf, 24);
	MSCP_LOG_MSG("1:DFM_Read_eeprom ret = %d\n",ret);
	(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_EEPROMCPU, 24u, rBuf);
	if(g_PFM_Cfg.CPU_ID == 1)
	{
		ret = DFM_Read_eeprom(2, rBuf, 24);
		MSCP_LOG_MSG("2:DFM_Read_eeprom ret = %d\n",ret);
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_EEPROMIO12S, 24u, rBuf);
	}
	else
	{
		ret = DFM_Read_eeprom(3, rBuf, 24);
		MSCP_LOG_MSG("3:DFM_Read_eeprom ret = %d\n",ret);
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_EEPROM8S, 24u, rBuf);
		ret = DFM_Read_eeprom(4, rBuf, 24);
		MSCP_LOG_MSG("4:DFM_Read_eeprom ret = %d\n",ret);
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_EEPROMIO12S, 24u, rBuf);
	}
}
/*
 * @brief板卡硬件自检 3次
 */
void PFM_BoardCheck_TolerateThreetimes(void)
{
	/*- 网卡状态自检 */
	DFM_ethernetState();
	/* MSCP_LOG_MSG("ethernetState_CHECK_OK \r\n"); */
	/*- 电压状态自检 */
	DFM_voltageState();
	/* MSCP_LOG_MSG("voltageState_CHECK_OK \r\n"); */
	/*- 温度自检*/
	PFM_BoardTmpCheck();
	/* MSCP_LOG_MSG("BoardTmp_CHECK_OK \r\n"); */
}
void PFM_InitSignalFunc(void)
{
#ifdef QNX
	/*注册信号处理函数*/
	act.sa_flags=0; /*表示使用act.sa_handler形式的信号处理函数 */
	act.sa_handler=signal_handler;
	(void)sigemptyset(&act.sa_mask); /*清空sa_mask信号屏蔽集*/
	/*由应用注册*/
#if 0
	(void)sigaction(SIGSEGV,&act,NULL);
	(void)sigaction(SIGBUS,&act,NULL);
	(void)sigaction(SIGABRT,&act,NULL);
#endif
	/*设置标准输出和错误输出为无缓冲*/
	(void)setvbuf(stdout,NULL,_IONBF,0u);
	(void)setvbuf(stderr,NULL,_IONBF,0u);
#endif
}

/**
* @brief 设置捕获信号
*/
void PFM_SetSignal(CM_INT32 SIGNAL)
{
#ifdef QNX
	(void)sigaction(SIGNAL,&act,NULL);
#endif
}

/**
* @brief 设置应用运行步骤
*/
void PFM_SetAppCheck(CM_INT32 appCheck)
{
	s_PFM_AppCheck = appCheck;
}
/**
* @brief 信号处理函数
* @details 宕机捕获信号不让程序宕机，追踪宕机位置
*/
static void signal_handler(void)
{
	static FILE * fp_crash;
	static CM_CHAR str_crash[256] = {0};
	static CM_UINT8 ret = 0u;
	(void)printf("PFM_CFC_Check = %d\n", g_PFM_Check);
	MSCP_LOG_MSG("PFM_CFC_Check = %d\n", g_PFM_Check);

	(void)printf("PFM_CFC_Check = %d\n", s_PFM_AppCheck);
	MSCP_LOG_MSG("PFM_CFC_Check = %d\n", s_PFM_AppCheck);

	fp_crash = fopen("signallog.txt", "w+");
	(void)sprintf(str_crash,"PFM_CFC_Check = %d, s_PFM_AppCheck = %d\n", g_PFM_Check, s_PFM_AppCheck);
	ret=fwrite(str_crash,(CM_SIZE_T)1u,strlen(str_crash),fp_crash);
	if (ret != strlen(str_crash))
	{
		MSCP_LOG_MSG("fwrite signallog.txt fail!\n");
		(void)printf("fwrite signallog.txt fail!\n");
	}
	else
	{
		/*- 无处理 */
	}
	(void)fclose(fp_crash);

	CM_NM_ASSERT(0, SELF_CHECK_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_1);
	while(1)
	{
		CM_Sleep(CM_UINT32_MAX);
	}
}

