/*
 * DFM_DRV_QNX.c
 *
 *  Created on: 2021�?8�?24�?
 *      Author: happy
 */
#include "DFM_DRV.h"
#ifdef QNX
#include "imx8_drv_gpio.h"
#include "imx8_drv_i2c.h"
#include "CFM_Net.h"
#include "CM_Time.h"
#include "CM_Memory.h"
#include "DFM_Time.h"
#include "PFM_Log.h"
#include "PFM_Cfg.h"
#include "PFM_SelfCheck.h"
extern char drv_vsr[4];
extern CM_UINT8 MSCP_DRV_VERION[4];
CM_UINT8 g_OutIoLog = 0;
CM_UINT16 g_InIoLog = 0;
/**
* @brief 驱动初始化
*
*/
void DFM_drv_Init(void)
{
	CM_INT32 rtn = 0;
	rtn = imx8_gpio_init();
	CM_NM_ASSERT(0 == rtn, QNX_DRV_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_1);
	rtn = imx8_i2c_init();
	CM_NM_ASSERT(0 == rtn, QNX_DRV_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_2);
	rtn = imx8_create_timer_pthread_25();
	CM_NM_ASSERT(0 == rtn, QNX_DRV_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_3);
	rtn = imx8_cpu_temp_init();
	CM_NM_ASSERT(0 == rtn, QNX_DRV_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_4);
	MSCP_DRV_VERION[0] = drv_vsr[0];
	MSCP_DRV_VERION[1] = drv_vsr[1];
	MSCP_DRV_VERION[2] = drv_vsr[2];
    MSCP_DRV_VERION[3] = drv_vsr[3];

    PFM_CFG_IfconfigIp();
	/*- 注册信号处理函数以及设置标准输出和错误输出为无缓冲 */
	PFM_InitSignalFunc();
	/* 延时等待任务创建 */
	CM_Sleep(3000u);

}

/**
* @brief 读取插箱板卡id
* @return 板卡插箱id
*
*/
CM_UINT8 DFM_getBoardID(void)
{
	CM_UINT8 boardId = 0u;
	boardId = imx8_read_boardID();
	return boardId;
}

/**
* @brief 检测输入通道的状态
* @param channel 通道数 取值范围：1~10
* @return 返回输入通道状态 取值范围：0或1
*/
CM_INT32 DFM_input(CM_UINT8 channel)
{
	CM_INT32 state = 0;
	CM_UINT16 value = 0;
	CM_INT32 ret = -1;
	if((channel >= 1) && (channel <= 10))
	{
		/*- 变量初始化 */
		state = imx8_input_collect(channel);
		value = 1UL << (channel-1);
		/*- 从左到右第channel-1位等于value*/
		if(1 == state)
		{
			g_InIoLog = g_InIoLog | value;
		}
		else if(0 == state)
		{
			g_InIoLog = g_InIoLog & (~value);
		}
		else
		{
			MSCP_LOG_MSG("DFM_input Waring It's neither 0 nor 1 \n");
		}
		/*MSCP_LOG_MSG("g_InIoLog = %x\n",g_InIoLog);*/
		ret = state;
	}
	else
	{
		MSCP_LOG_MSG("Illegal channel \n");
		ret = -1;
	}

	return ret;
}

/**
* @brief 检测输出通道的状态
* @param channel 通道数
* @param level 高低电平
* @return 返回输出通道状态
*/
CM_INT32 DFM_output(CM_UINT8 channel, CM_UINT8 level)
{
	if((channel >= 1) && (channel <= 8))
	{
		/*- 变量初始化 */
		CM_UINT8 value = 1UL << (channel-1);
		/*- 从左到右第channel-1位等于value*/
		if(1 == level)
		{
			g_OutIoLog = g_OutIoLog | value;
		}
		else if(0 == level)
		{
			g_OutIoLog = g_OutIoLog & (~value);
		}
		else
		{
			MSCP_LOG_MSG("DFM_output Waring It's neither 0 nor 1 \n");
		}
		/*MSCP_LOG_MSG("g_OutIoLog = %x\n",g_OutIoLog);*/
		return imx8_output(channel, level);
	}
	else
	{
		MSCP_LOG_MSG("Illegal channel \n");
		return -1;
	}
}
/**
* @brief 检测输入通道的状态
* @param outPutBuf 接收IO输入的buf指针
* @param len 指针缓冲区长度
* @return 返回输出通道状态 取值范围：成功0，失败-1
*/
CM_INT32 DFM_GetIO_InPut(CM_UINT8 *outPutBuf,CM_UINT8 len)
{
	/*- 变量初始化 */
	CM_INT32 ret = -1;
	CM_INT32 value = -1;
	CM_UINT8 i = 0u;
	if((outPutBuf != NULL) && (len >= 10u))
	{
		for(i = 0u;i < 10u;i++)
		{
			value = DFM_input(i + 1u);
			if(-1 == value)
			{
				(void)CM_Memset(outPutBuf,0u,10u,len);
				break;
			}
			else
			{
				outPutBuf[i] = value;
			}
		}
		ret = 0;
	}
	else
	{
		ret = -1;
	}
	/*- 获取通道状态  */
	return ret;
}
/**
* @brief 检测输出通道的状态
* @param level 前4通道的高低电平 取值范围：0~0xff
* @return 返回输出通道状态 取值范围：成功0，失败-1
*/
CM_INT32 DFM_SetIO_OutPut(CM_UINT8 level)
{
	/*- 变量初始化 */
	CM_INT32 ret = -1;
	ret |= DFM_output(4,level&0x01);
	ret |= DFM_output(3,(level>>1)&0x01);
	ret |= DFM_output(2,(level>>2)&0x01);
	ret |= DFM_output(1,(level>>3)&0x01);
	/*- 获取通道状态  */
	return ret;
}
/**
* @brief run闪灯
*
*/
void DFM_ledRun(void)
{
	static CM_INT8 sFlag = 0x55;
	CM_UINT8 lightState = 0x55U;
	CM_UINT8 lightPs = 0x55;
    if(0x55==sFlag)
	{
    	imx8_led_REA_REB(1);
	}
	else
	{
		imx8_led_REA_REB(0);
	}
    (void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_RUNLIGHT, 1U, &lightState);
    (void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_PSLIGHT, 1U, &lightPs);
    sFlag =~sFlag;
}

/**
* @brief 看门狗指示灯(2取)
*
*/
void DFM_ledMonitor(CM_UINT8 light)
{
	CM_UINT8 lightState = 0u;
	if(1u == light)
	{
		lightState = 0x55U;
	}
	else
	{
		lightState = 0xAAU;
	}
	(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_2OLIGHT, 1U, &lightState);
	(void)imx8_led_R_E(light);
}


/**
* @brief 主备指示灯
*
*/
void DFM_ledMS(CM_UINT8 light)
{
	CM_UINT8 lightState = 0u;
	if(3u == light)
	{
		lightState = 0xAAU;
	}
	else if(1u == light)
	{
		lightState = 0x55U;
	}
	else
	{
		lightState = 0xFFU;
	}
	(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_2XLIGHT, 1U, &lightState);
    (void)imx8_led_M_S(light);
}
/**
* @brief error灯点亮(run灯)
*
*/
void DFM_ledError(void)
{
	CM_UINT8 lightState = 0xAAU;
	(void)imx8_led_REA_REB(2);
	(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_RUNLIGHT, 1U, &lightState);
}

/**
* @brief 检查网卡1到网卡4状态
*
*/
void DFM_ethernetState(void)
{
	CM_UINT8 state = 0xAAu;
	static CM_UINT8 err_cut[4u] = {0u};
	static unsigned int (*ethernet_switch_state[4u])(void) =\
	{imx8_ethernet_switch_state_1_1,
	 imx8_ethernet_switch_state_1_2,
	 imx8_ethernet_switch_state_2_1,
	 imx8_ethernet_switch_state_2_2};
	CM_UINT8 i = 0u;
	CM_INT32 rtn = 0;
	PFM_LOG_SET_STOPTIMER(TSCP_DARK_ETHERNET);
	for(i = 0u;i < 4u;i++)
	{
		rtn = ethernet_switch_state[i]();
		if(1 == rtn)
		{
			err_cut[i] = 0u;
			state = 0x55u;
			(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_ETHERNET, 1u, &state);
		}
		else
		{
			err_cut[i]++;
			if(err_cut[i] >= 3u)
			{
				/*宕机*/
				MSCP_LOG_MSG("SelfCheck-eth1-1:%d,eth1-2:%d,eth2-1:%d,eth2-2:%d\n",err_cut[0],err_cut[1],err_cut[2],err_cut[3]);
				(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_ETHERNET, 1u, &state);
				CM_NM_ASSERT(0, QNX_DRV_MODE, DARK_FAULT_CODE_FUN_ORDER_2, i + 1u);
			}
			else
			{
				/*- 无处理*/
				MSCP_LOG_MSG("SelfCheck-eth1-1:%d,eth1-2:%d,eth2-1:%d,eth2-2:%d\n",err_cut[0],err_cut[1],err_cut[2],err_cut[3]);
			}
		}
	}
	PFM_LOG_SET_STOPTIMER(TSCP_DARK_NULL);
}

/**
* @brief 检查12V,24V,5V,3.3V,电压状态
*
*/
void DFM_voltageState(void)
{
	CM_UINT8 state = 0xAAu;
	static CM_UINT8 err_cut[7u] = {0u};
	static unsigned int (*voltage_state[7u])(void) =\
	{imx8_5V_overvoltage_state,				/*- 5V过压自检*/
	 imx8_5V_undervoltage_state,			/*- 5V欠压自检*/
	 imx8_24V_voltage_state,				/*- 24V电压状态自检*/
	 imx8_Safe_gate_overvoltage_state_1,	/*- 安全电压过压自检_1*/
	 imx8_Safe_gate_undervoltage_state_1,	/*- 安全电压欠压自检_1*/
	 imx8_Safe_gate_overvoltage_state_2,	/*- 安全电压过压自检_2*/
	 imx8_Safe_gate_undervoltage_state_2};	/*- 安全电压欠压自检_2*/
	CM_UINT8 i = 0u;
	CM_INT32 rtn = 0;
	PFM_LOG_SET_STOPTIMER(TSCP_DARK_VOLTAGE);
	for(i = 0u;i < 7u;i++)
	{
		rtn = voltage_state[i]();
		if(1u == rtn)
		{
			/*- 正常 */
			err_cut[i] = 0u;
			state = 0x55u;
			(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_VOLTAGE, 1u, &state);
		}
		else
		{
			err_cut[i]++;
			if(err_cut[i] >= 3u)
			{
				/*- 宕机 */
				MSCP_LOG_MSG("SelfCheck-5V_over:%d,5V_under:%d,24V_voltage:%d,Safe_over_1:%d,Safe_under_1:%d,Safe_over_2:%d,Safe_under_2:%d\n",err_cut[0],err_cut[1],err_cut[2],err_cut[3],err_cut[4],err_cut[5],err_cut[6]);
				(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_VOLTAGE, 1u, &state);
				CM_NM_ASSERT(0, QNX_DRV_MODE, DARK_FAULT_CODE_FUN_ORDER_3, i + 1u);
			}
			else
			{
				/*- 无处理*/
				MSCP_LOG_MSG("SelfCheck-5V_over:%d,5V_under:%d,24V_voltage:%d,Safe_over_1:%d,Safe_under_1:%d,Safe_over_2:%d,Safe_under_2:%d\n",err_cut[0],err_cut[1],err_cut[2],err_cut[3],err_cut[4],err_cut[5],err_cut[6]);
			}
		}
	}

	PFM_LOG_SET_STOPTIMER(TSCP_DARK_NULL);
}


/**
* @brief 获取主机板板卡表面温度
*
*/

CM_FLOAT64 DFM_Get_Tmp112(void)
{
	CM_FLOAT64 tmp = (CM_FLOAT64)0;
	tmp = imx8_read_tmp112();
	return tmp;
}

/**
* @brief 获取IO板卡表面温度
*
*/

CM_FLOAT64 DFM_Get_Tmp117(void)
{
	CM_FLOAT64 tmp = (CM_FLOAT64)0;
	tmp = imx8_read_tmp117();
	return tmp;
}

/**
* @brief 安全关断
*
*/
void DFM_saftyOff(void)
{
	/*- 停止反转gpio定时器+加个反馈打印 */
	(void)printf("---------------- Safty Off ----------------\n");
	(void)imx8_safty_ethernet_off();
}

/**
* @brief 采集按钮状态
* @return 采集的按钮状态 取值范围：1为按下 0为未按下
*/
CM_INT32 DFM_switchButton(void)
{
	/*- 变量初始化 */
	static CM_UINT32 s_birthCount = 0u;
	static CM_INT32 s_State = 0;
	CM_UINT32 birthCount = DFM_GetBirthCount();
	CM_UINT8 switchState = 0u;
	/*- 采集按钮状态 */
	CM_INT32 ret = imx8_switch_button();
	/*- 如果周期发生改变或切系按钮状态发生改变 */
	if((birthCount != s_birthCount) || (ret != s_State))
	{
		/*- 将切系状态发送给维护机*/
		s_birthCount = birthCount;
		s_State = ret;
		switchState = (1 == ret)?0x55u:0xAAu;
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_SWITCHBUTTON, 1U, &switchState);
	}
	/*- 返回切系状态 */
	return ret;
}
/**
* @brief 通道电流电压读取
* @param channel_1_shunt 核心3.3V电流 取值范围:-16~16
* @param channel_1_bus 核心3.3V电压 取值范围:0~26
* @param channel_2_shunt IO3.3V电流 取值范围:-16~16
* @param channel_2_bus IO3.3V电压 取值范围:0~26
* @param channel_3_shunt 核心5v电流 取值范围:-16~16
* @param channel_3_bus 核心5v电压 取值范围:0~26
* @return 返回结果 取值范围：0成功,-1失败
*/
CM_INT32 DFM_Read_ina3321(INOUT CM_INT32* channel_1_shunt, INOUT CM_FLOAT32* channel_1_bus, INOUT CM_INT32* channel_2_shunt, INOUT CM_FLOAT32* channel_2_bus, INOUT CM_INT32* channel_3_shunt, INOUT CM_FLOAT32* channel_3_bus)
{
	/*- 变量初始化 */
	CM_INT32 ret = -1;
	struct ina3221 ina332_value;
	/*- 防空检查 */
	if((channel_1_shunt == NULL) || (channel_1_bus == NULL) || (channel_2_shunt == NULL) ||
		(channel_2_bus == NULL) || (channel_3_shunt == NULL) || (channel_3_bus == NULL))
		{
			ret = -1;
		}
		else
		{

			/*- 通道电流电压读取 */
			ret = imx8_read_ina3221(&ina332_value);
			*channel_1_shunt = ina332_value.channel_1_shunt;
			*channel_1_bus = ina332_value.channel_1_bus;
			*channel_2_shunt = ina332_value.channel_2_shunt;
			*channel_2_bus = ina332_value.channel_2_bus;
			*channel_3_shunt = ina332_value.channel_3_shunt;
			*channel_3_bus = ina332_value.channel_3_bus;
		}
	return ret;
}

/**
* @brief 将信息写入到eeprom中
* @param board 取值范围：EEPROM_IN_BOARD  1 本cpu信息
                        EEPROM_OUT_BOARD 2 cpu1调用对应io板信息
                                         3 cpu2调用12R交换机板信息
                                         4 cpu2调用8R交换机板信息
* @param tx_buf 写入的信息 取值范围：非空
* @param len 写入信息的长度 取值范围:0~0xffffffff
* @return 返回结果 取值范围：0成功,-1失败
*/
CM_INT32 DFM_Write_eeprom(IN CM_INT32 board, IN CM_UINT8 wBuf[], IN CM_UINT32 len)
{
	CM_INT32 ret = 0;
	if(NULL != wBuf)
	{
		ret = imx8_write_eeprom(board, wBuf, len);
	}
	else
	{
		MSCP_LOG_MSG("wBuf is NULL\n");
	}
	return ret;
}

/**
* @brief 从eeprom中读取信息
* @param board 取值范围：EEPROM_IN_BOARD  1 本cpu信息
                        EEPROM_OUT_BOARD 2 cpu1调用对应io板信息
                                         3 cpu2调用8R交换机板信息
                                         4 cpu2调用12R交换机板信息
* @param rBuf 读出的信息 取值范围：非空
* @param len 读出信息数组的大小 取值范围:0~0xffffffff
* @return 返回结果 取值范围：0成功,-1失败
* @details
* len的长度是多长,函数就从eeprom读多大,里面的信息以及信息大小,需要在工装写的时候就定好
*/
CM_INT32 DFM_Read_eeprom(IN CM_INT32 board, OUT CM_UINT8 rBuf[], IN CM_UINT32 len)
{
	CM_INT32 ret = 0;
	ret = imx8_read_eeprom(board, rBuf, len);
	return ret;
}

/**
* @brief 读取cpu温度
* @return 返回cpu温度 取值范围：0~105
*/
CM_INT32 DFM_Read_cputemp(void)
{
	/*- 变量初始化 */
	CM_INT32 temp = 0;
	/*- 获取cpu温度 */
	temp = imx8_read_cpu_temp();
	/*- 返回cpu温度 */
	return temp;
}

#endif

/**
* @brief 驱动周期发送log
*/
void DFM_Drv_CycLog(void)
{
	/*- 周期发送驱动log */
	MSCP_LOG_MSG("drv verson:%d.%d.%d.%d\n",drv_vsr[0],drv_vsr[1],drv_vsr[2],drv_vsr[3]);
	(void)CFM_DarkLog_Storage(DARK_LOG_STRING, TSCP_DARK_DRVVERION, 4U, drv_vsr);
	(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_IOOUTPUT, 1U, &g_OutIoLog);
	(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_IOINPUT, 2U, &g_InIoLog);
}
/*
* @brief 将读取到的字符串版本号转换为数字
* @param str 要分割的字符串 取值范围：非空
* @param numbers 输出转换完成的版本号空间：非空
* @return 返回结果 取值范围：无
 */
void QNX_Version_to_Numbers(CM_UINT8 *str, CM_UINT8 numbers[])
{
	/*- 变量初始化*/
	CM_CHAR segment[3];
    CM_UINT8 i = 0;
    const CM_CHAR *delim = ".";
    CM_CHAR *token;

    /* 按 . 分割字符串。*/
    token = strtok((CM_CHAR *)str, delim);
    while (token != NULL && i < 4u)
    {
        (void)strncpy(segment, token, 2);
        segment[2] = '\0'; /*将每个分割得到的段（即数字）复制到 segment 数组中，并确保其以空字符结尾。*/

        /*转换*/
        numbers[i] = (CM_UINT8)atoi(segment);

        /*下移*/
        token = strtok(NULL, delim);
        i++;
    }
}
/*
 * 读取系统版本号
 */
ENUM_CM_RETURN DFM_GetQNX_Verion(CM_UINT8 *buf)
{
	/*- 变量初始化*/
	ENUM_CM_RETURN rtn = ENUM_CM_FALSE;
	CM_INT32 fd = 0;
	CM_SIZE_T get_size = 0;
	CM_UINT8 i = 0u;
	CM_UINT8 tmpbuf[20] = {0u};

	if(buf != NULL)
	{
		/* 以只读模式打开*/
		fd = open("/etc/version", O_RDONLY);
		if(-1 == fd)
		{
			MSCP_LOG_MSG("can't open version because: %s \n", strerror(errno));
		}
		else
		{
			get_size = read(fd, tmpbuf, (CM_SIZE_T)10);
			if(0 < get_size)
			{
				for(i = 0u; i < 10u; i++)
				{
					if(tmpbuf[i] == '\n')
					{
						tmpbuf[i] = '\0';
						break;
					}
					else
					{
							;
					}
				}
				QNX_Version_to_Numbers(tmpbuf, buf);
				/* 读取成功 */
				rtn = ENUM_CM_TRUE;
			}
			else
			{
				MSCP_LOG_MSG("read version fail get size = %d\n",get_size);
			}
			(void)close(fd);
		}
	}
	else
	{
		MSCP_LOG_MSG("buf is NULL !!!\n");
	}


	return rtn;
}

/*
 * 用来检测fec0 fec1 up/down状态
 */
void DFM_Network_Check(void)
{
	char  pFileBuf[1000] = { 0u };
	const char *filename = "networkcheck.txt";
    (void)system("drvtools -linkfec0 3 > networkcheck.txt");
    (void)system("drvtools -link9131 3 >> networkcheck.txt");

    FILE *file = fopen(filename, "r");
    if(NULL == file)
    {
    	printf("open networkcheck.txt error\n");
    }
    else{
    while (NULL != fgets(pFileBuf, sizeof(pFileBuf), file)) {
		if('w' != pFileBuf[0])
		{
			MSCP_LOG_MSG("%s", pFileBuf);
			(void)printf("%s", pFileBuf);
		}
		else
		{
			/* 不做处理,过滤无用数据 */
		}
    }
    /* 关闭文件 */
	(void)fclose(file);
    }
    return;
}
