/**
* @file MSCP_main.c
* @brief TSCP安全平台主程序入口
* @details
* 上电初始化和周期应用、周期自检主逻辑入口
* @author GT-BU
* @date 2021.02.20
* @version V1.0
* @copyright TCT
* @par 修改日志
* <table>
* <tr><th>Date        <th>Version  <th>Author     <th>Description
* <tr><td>2021.02.01  <td>V1.0     <td>GT-BU      <td>创建初始版本
* </table>
*/
#include "MSCP_main.h"
#include "CM_Types.h"
#include "CM_Atomic.h"
#include "CM_MultiThread.h" /* pthread */
#include "CM_Sem.h"
#include "CM_Convert.h"
#include "CM_Memory.h"
#include "CM_Time.h"
#include "DFM_Time.h"
#include "CFM_Net.h"
#include "PFM_Log.h"
#include "PFM_Cfg.h"
#include "SFM_2oo2.h"
#include "SFM_2x2.h"
#include "SFM_Prtcl.h"
#include "PFM_InputOutput.h"
#include "PFM_ControlFlowCheck.h"
#include "PFM_CPUCheck.h"
#include "PFM_MemCheck.h"
#include "DFM_DRV.h"
#include "PFM_MemoryCheck.h"
#include "PFM_SelfCheck.h"
#include "CM_Com.h"
#include "PFM_CPUUsage.h"
#include "SFM_Prtcl.h"
#include "PFM_RemoteUpdate.h"
#if QNX
#include <sys/neutrino.h>
#include <sys/trace.h>
#include <sys/neutrino.h> /* ThreadCtl BMP绑定CPU*/
#endif
/* 应用任务管理信息 */
typedef struct
{
    void* p_core_mask;    /* 绑定的CPU内核 */
    ENUM_CM_RETURN(*pAppfunc)(void); /* 应用周期调用函数 */
    CM_SEM_T m_appStart;  /* 应用开始信号量 */
    CM_SEM_T m_appStop;   /* 应用结束信号量 */
    CM_UINT64 m_appStart_Time;/* 应用开始时间 */
    CM_UINT64 m_appStop_Time;/* 应用结束时间 */
}STRU_APP_CTRL_T;

/* 自检管理信息 */
typedef struct
{
    CM_SEM_T m_selfCheckStart;  /* 自检开始信号量 */
    CM_SEM_T m_selfCheckStop;   /* 自检结束信号量 */
}STRU_SELF_CHECK_CTRL_T;

/* 自检管理信息 */
typedef struct
{
	STRU_SELF_CHECK_CTRL_T selfCheck;  /* 自检信号量 */
	void* p_core_mask;    /* 绑定的CPU内核 */
}STRU_CPU_SELF_CHECK_CTRL_T;

/* 应用任务管理信息 */
static STRU_APP_CTRL_T s_appCtrl[10];

/* CPU自检任务管理信息 */
static STRU_CPU_SELF_CHECK_CTRL_T s_CpuCheckCtrl[10];

/* 自检管理管理信息 */
static STRU_SELF_CHECK_CTRL_T s_selfCheck_Ctrl;

extern CM_UINT32 g_MSCP_SysCount; /**< 系统周期号 */
extern CM_UINT32 g_MSCP_BirthCount; /**< 上电周期号 */
extern const CM_UINT8 MSCP_SW_VERION[4];
extern CM_UINT16 TSCP_DOC_VERION[2];
/** 热备状态字符串 */
/*static const char s_2x2stat_str[][20] = { "SHUTDOWN","OFFLINE","PRE_MASTER","MASTER","SLAVE" };*/

/* 初始化 */
static void MSCP_Init(void);

/* 并行多任务平台 */
static CM_THREAD_FUNC_T MSCP_CycBase(void);

/* 并行多任务应用 */
static CM_THREAD_FUNC_T MSCP_CycApp(IN CM_Thread_Arg_Struct_T* arg);

/* 主自检线程 */
static CM_THREAD_FUNC_T MSCP_CheckMain(IN CM_Thread_Arg_Struct_T* arg);
/* 从自检线程 */
static CM_THREAD_FUNC_T MSCP_CheckPeer(IN CM_Thread_Arg_Struct_T* arg);

/* 应用调度初始化 */
static void s_appCtrlInit(void);

/* 逻辑处理微周期 */
static void s_LogicProc(ENUM_CM_RETURN (*pAppfunc)(void));

/* 自检初始化 */
static void s_SelfCheckCtrlInit(void);

/* cpu自检初始化 */
static void s_CpuCheckCtrlInit(void);

/* 自检初始化 */
static void SelfCheckInit(void);

static void selfCheckSemWait(void);

static void selfCheckSemPost(void);
/**
* @brief 主程序入口
* @details 调用初始化入口和周期循环入口
*/
#if WIN32
int mscp_main(void)
#else
int main(void)
#endif
{
	CM_BOOL rt = CM_FALSE;
#if QNX
    void* pmask = NULL;
    struct sched_param params;    /* 线程调度参数 */
    /*- 本线程锁定在 A53 core 0 */
    pmask = (void*)0x01;
    (void)ThreadCtl(_NTO_TCTL_RUNMASK, pmask);
    /*- 设置线程优先级 */
    params.sched_priority = CM_TASK_PRIORITY_89;
    /*- 设置线程调度模式为轮询模式 */
    (void)sched_setscheduler(0,SCHED_RR,&params);
#endif
    /*- 上电读取和删除本地日志文件*/
    MSCP_Read_Del_Logfile();
	/*- 初始化入口 */
	MSCP_Init();
	/*- 创建安全平台主线程 */
	rt = CM_Thread_Create((CM_THREAD_T*) NULL, (CM_THREAD_FUNC_T) MSCP_CycBase,"main", 0, CM_TASK_PRIORITY_73, NULL);
	CM_RE_ASSERT(CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_3);
	CM_Sleep(100u); /* 延时等待任务创建 */

	/*- 创建看门狗状态监督线程 */
	rt = CM_Thread_Create((CM_THREAD_T*) NULL, (CM_THREAD_FUNC_T) MSCP_WatchDog,"watchdog", 0, CM_TASK_PRIORITY_89, NULL);
	CM_RE_ASSERT(CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_4);
	CM_Sleep(100u); /* 延时等待任务创建 */
	
	/*- 平台状态监督 */
	PFM_CFC_Monitor();
	/* 此后代码不可达 */
	/*- @alias 主函数循环休眠 */
	while (1) 
	{
		CM_Sleep(CM_UINT32_MAX);
	}
	/* 此处不可达 */
	return 0;
}
/**
* @brief 上电初始化主入口
* @details
* 调用各模块（包括应用）的上电初始化接口
*/
static void MSCP_Init(void)
{
    /*- 变量初始化 */
    ENUM_CM_RETURN ret = ENUM_CM_FALSE; /* 函数返回值 */
    CM_UINT8 vitalBuf[200] = { 0u }; /* 关键变量数组 */
    CM_UINT16 vitalLen = 0u; /* 关键变量长度 */
    CM_UINT64 cycTick = 0u; /* 周期开始时间 */
    CM_UINT8 state = 0x55U;
	
    /*- 驱动初始化 */
    DFM_drv_Init();
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_DRV);
    CM_Sleep(10u);
    /*- 维护队列初始化，必须提前*/
    CFM_Maintain_Queue_Init();
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_MAIN_QUEUE_NET);
    PFM_LOG_SET_STOPTIMER(TSCP_DARK_TSCPINIT);
    /*- 应用版本号初始化，必须在应用软件初始化前 */
    PFM_CFG_RegisterVerson_Init();
	/*- 初始化读取main id，在应用初始化之前*/
	PFM_CFG_MAINID_Init();
    /*- 应用软件初始化内网安全协议参数-以及配置文件参数 */
    APP_API_Data_Init();
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_API_DATA);
    /*- 平台配置文件管理初始化 */
    PFM_CFG_Init();
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_CFG);
    /*- 网卡初始化 */
    CFM_NetworkCard_Init();
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_NETCARD);
    /*- 维护网日志发送初始化 */
    CFM_Maintain_Init();
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_MAIN_NET);
    /*- 控制流状态监督初始化 */
    PFM_CFC_Init();
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_CFC);
    /*- 是否开启2x2功能 */
    if (0x55u == g_PFM_Cfg.M_2x2_Enable)
    {
#ifdef QNX
		/*- 串口通信初始化*/
		(void)CM_COM_INIT(115200u, 8u);
		PFM_LOG_SET_INIT_STAGE(ENUM_INIT_COM);
#endif /*QNX*/
    }
    /*- 微周期控制初始化 */
    PFM_Init();
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_MICROCYCLE);
    /*- 内网安全协议初始化 */
    SFM_PrtclInInit(p_gSfpInnetPara);
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_PRTCL_SFP);
    PFM_LOG_SET_STOPTIMER(TSCP_DARK_NULL);
    (void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_TSCPINIT, 1U, &state);
    PFM_LOG_SET_STOPTIMER(TSCP_DARK_SOFTTNIT);
    /*- CFM:网络通信初始化 */
    CFM_UpdateAnd2oo2_Net_Init();
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_UPDATE_NET);
    /*- 2取数据初始化  */
    SFM_2oo2_DataInit();
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_2OO2_DATA);
    CFM_Net_Init();
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_NET);
    /*- 上电自检初始化 */
    SelfCheckInit();
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_SELFCHECK);
    /*- 应用软件初始化 */
	ret = APP_API_Init(vitalBuf, &vitalLen);
	MSCP_LOG_MSG("APP init...%s\n", ((ENUM_CM_TRUE == ret) ? "success" : "fail"));
	CM_ASSERT(ENUM_CM_TRUE == ret, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_1);
	PFM_LOG_SET_INIT_STAGE(ENUM_INIT_APP);
	/*- 外网安全协议初始化 */
	SFM_PrtclOutInit();

	PFM_LOG_SET_INIT_STAGE(ENUM_INIT_PRTCL_RSSP);
    /*- 应用调度初始化(必须在应用软件初始化后) */
    s_appCtrlInit();

    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_APP_CTRL);
    /*- 是否开启2x2功能 */
    if (0x55u == g_PFM_Cfg.M_2x2_Enable)
    {
#ifdef QNX

		/*- 开启临机串口接收线程*/
		CM_Com_RcvOtherThreadInit();
		PFM_LOG_SET_INIT_STAGE(ENUM_INIT_2X2USART);
#endif
    }
    /*- 是否开启2oo2功能 */
    if (0x55u == g_PFM_Cfg.M_2oo2_Enable)
    {
        /*- 2oo2初始化、上电同步和上电比较 */
    	PFM_LOG_SET_STOPTIMER(TSCP_DARK_2oo2INIT);
        SFM_2oo2_Init(vitalBuf, vitalLen, &cycTick);
        PFM_LOG_SET_INIT_STAGE(ENUM_INIT_2OO2);
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_2oo2INIT, 1u, &state);
    }
    else
    {
        /*- 默认上电同步时刻为当前时刻 */
        cycTick = CM_GetTick();
        /*设置UTC基础时间*/
        CM_ATOMIC_STORE(&g_UTCBaseTick, CM_GetUTCTick());
        MSCP_LOG_MSG("g_UTCBaseTick:%lld us\n", g_UTCBaseTick);
        MSCP_LOG_MSG("cycTick:%lld us\n", cycTick);
    }
    PFM_LOG_SET_STOPTIMER(TSCP_DARK_SOFTTNIT);
    /* 至此确定了2oo2同步的完成时刻 */
    /*- 2x2上电比较和计算时钟修正量 */
    SFM_2x2_Init(vitalBuf, vitalLen, &cycTick);
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_2X2);
    (void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_SOFTTNIT, 1U, &state);
    PFM_LOG_SET_STOPTIMER(TSCP_DARK_NULL);
    /*- 保存周期基准时刻 */
    PFM_LOG_SET_INIT_STAGE(ENUM_INIT_OVER);
    CM_ATOMIC_STORE(&g_CycBaseTick, cycTick); /* parasoft-suppress GJB8114-R_1_7_2 NAMING-22 "QNX宏不符合编码规范" */
    /*此处至周期开始延时不可以超过一个周期的时间，最好不要加延时*/
}

/**
* @brief 平台任务
* @details
* 平台输入微周期处理和输出微周期处理
*/
static CM_THREAD_FUNC_T MSCP_CycBase(void)
{
	/*- 变量初始化 */
	CM_UINT64 costlog[20];    /* 耗时记录 */
	CM_INT32 delayTime = 0;   /* 延迟时间 */
	CM_UINT64 leftTime = 0u;    /* 剩余时间 */
	CM_INT64 offset_2oo2 = 0; /* 2oo2时钟修正量 */
	CM_INT64 offset_2x2 = 0;  /* 2x2时钟修正量 */
	CM_INT32 i = 0;           /* 循环变量 */
	ENUM_2x2_STATE_T localState = ENUM_2x2_SHUTDOWN;
	ENUM_2x2_STATE_T peerState = ENUM_2x2_SHUTDOWN;
	ENUM_CM_RETURN rt = ENUM_CM_FALSE;
	CM_UINT32 darkInPutTime = 0u;
	CM_UINT32 darkOutPutTime = 0u;
	CM_UINT32 darkCycEndTime = 0u;
	CM_UINT8 darkAppTimeBuf[20] = {0U};
	CM_UINT32 tempAppTimeBuf[5] = {0U};
	CM_UINT32 u_64temp = g_PFM_Cfg.CYC_TIME * CM_UNSIGNED_MILLION;    /*uint64临时变量*/
    CM_UINT8 state = 0x55u;
    CM_UINT8 drvBoard = DFM_getBoardID();
#if QNX
    void* pmask = NULL;
    /*- 本线程锁定在 A53 core 1 */
    pmask = (void*)0x02u;
    (void)ThreadCtl(_NTO_TCTL_RUNMASK, pmask);
#endif
    /*- 获取周期开始时刻 */
    g_CycTick = CM_ATOMIC_LOAD(&g_CycBaseTick); /* parasoft-suppress GJB8114-R_1_7_2 NAMING-22 "QNX宏不符合编码规范" */
    /*- 等待周期开始*/
    leftTime = DFM_WaitUntill(g_CycTick);
	PFM_SetBoardState(ENUM_BOARDSTATE_RUN);
	/*周期号必须从1开始*/
	g_MSCP_BirthCount = 1u;
	costlog[0] = CM_GetTick();
	costlog[1] = CM_GetTick();
	/*发送暗文日志*/
	CFM_LogCiphertextSend();
    /*- 喂狗 */
    PFM_CFC_WatchDog();
    /*- 清空通信缓冲区 */
    CFM_NetFlush();
	/*发送2x状态结束信号量*/
    SFM_2x2_SemPost();
	(void)DFM_SetIO_OutPut(0x00u);
    /*- 循环执行周期逻辑 */
    while (1)
    {
		/*- 更新周期号*/
		g_MSCP_SysCount++;
		localState = SFM_2x2_GetLocal2x2State();
		peerState = SFM_2x2_GetPartner2x2State();
		MSCP_LOG_MSG("time left:%lld us\n", leftTime);
		MSCP_LOG_MSG("==========CPU:%d-%d=CYC=%d==M/S:0x%x==Partner:0x%x============\n",g_PFM_Cfg.BOARD_ID,g_PFM_Cfg.CPU_ID,g_MSCP_SysCount,localState,peerState);
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_CYC, 4U, &g_MSCP_SysCount);
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_BOARDID, 1U, &drvBoard);
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_CPUID, 1U, &g_PFM_Cfg.CPU_ID);
		(void)CFM_DarkLog_Storage(DARK_LOG_STRING, TSCP_DARK_VERION, 4U, MSCP_SW_VERION);
		(void)CFM_DarkLog_Storage(DARK_LOG_STRING, TSCP_DARK_QNXVERION, 4U, TSCP_QNX_VERION);
		(void)CFM_DarkLog_Storage(DARK_LOG_STRING, TSCP_DARK_DOCVERION, 4U, TSCP_DOC_VERION);
		PFM_CFG_SendDarkCfg();
		PFM_GetAllCpuUsageInterface();/*发送cpu使用率接口*/
#if QNX
		CM_RE_ASSERT(leftTime > 1000u, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_1);
#endif
/*- ***********APP周期开始阶段***************/
         /*- 发送设备类型 */
		(void)PFM_DevStateSend(1);
		/*- 双缓冲区切换 */
		PFM_BufSwich();
		MSCP_LOG_MSG("timecurr 11 BufSwitch = %lld us\n", NOW_USED_TIME);
/*- ***********APP启动阶段*/
		/*#############应用启动#############*/
		MSCP_LOG_MSG("BASE_APP_RUN %lld us\n", NOW_USED_TIME);
		/*- @alias 发送应用启动信号*/
		for (i = 1; i <= g_PFM_Cfg.app_num; i++)
		{
			if(NULL == s_appCtrl[i].pAppfunc)
			{
				/*- 无处理*/
			}
			else
			{
				rt = CM_Sem_Post(s_appCtrl[i].m_appStart);
				CM_RE_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_2);
			}
		}
#ifdef QNX
		(void)trace_nlogf(122, 0, "app_start");
#endif
		/*#############LED运行电灯#############*/
		MSCP_LOG_MSG("timecurr 12 AppStart = %lld us\n", NOW_USED_TIME);
		DFM_ledRun();
/*- ***********输出数据处理阶段*/
		/*#############输出微周期#############*/
		/*- 输出微周期：协议层封装*/
		costlog[6] = CM_GetTick();
		SFM_EnPrtclProc();
		MSCP_LOG_MSG("timecurr 13 EnPrtclProc = %lld us\n", NOW_USED_TIME);
/*- ***********数据输出阶段*/
		/*- 输出微周期：输出数据处理*/
		PFM_OutputProc();
		costlog[7] = CM_GetTick();
		/*计算输出阶段耗时，并通过暗文日志发送*/
		darkOutPutTime = (CM_UINT32)CM_UNSIGNED_LONG_INT_EXP((costlog[7] - costlog[6]) / 1000u);
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_OUTTIME, 4U, &darkOutPutTime);
		MSCP_LOG_MSG("BASE_OUTPUT_SEND = %lld us\n", NOW_USED_TIME);
/*- ***********周期时间控制阶段-空闲微周期*/
		/*- 暗文标志位至为发送 */
		PFM_CFC_Check(22);
		/*发送暗文日志*/
		CFM_LogCiphertextSend();
		PFM_CFC_Check(23);
		MSCP_LOG_MSG("timecurr 18 Time = %lld us\n", NOW_USED_TIME);
		/*重置自动重启次数*/
		SFM_2oo2_Reset_AutoRbootCut();
		MSCP_LOG_MSG("timecurr 19 Time = %lld us\n", NOW_USED_TIME);
		/*- 空闲微周期：等待新周期开始 */
		if (0 != offset_2oo2)
		{
			CM_ATOMIC_ADD(&g_CycBaseTick, offset_2oo2); /* parasoft-suppress GJB8114-R_1_7_2 "QNX宏不符合编码规范" */
			MSCP_LOG_MSG("[%d]2oo2fix=%lld\n", g_MSCP_SysCount, offset_2oo2);
		}
		else
		{
			MSCP_LOG_MSG("0 == offset_2oo2\n");
		}

		if (0 != offset_2x2)
		{
			CM_ATOMIC_ADD(&g_CycBaseTick, offset_2x2); /* parasoft-suppress GJB8114-R_1_7_2 "QNX宏不符合编码规范" */
			MSCP_LOG_MSG("[%d]2x2fix=%lld\n", g_MSCP_SysCount, offset_2x2);
			if ((CM_ABS(offset_2x2)) >= (CM_INT64)u_64temp)
			{
				offset_2x2 = 0;
			}
			else
			{
				/*- 无处理 */
			}
		}
		else
		{
			MSCP_LOG_MSG("0 == offset_2x2\n");
		}
		MSCP_LOG_MSG("g_CycBaseTick = %lld\n",g_CycBaseTick);
		g_CycTick += (CM_UINT64)CM_SIGNED_LONG_INT_EXP(u_64temp + offset_2oo2 + offset_2x2);
		/*- 冗余喂狗，防止误判超时 */
		PFM_CFC_WatchDog();
/**************↓↓↓↓↓↓禁止添加代码，包括打印！***************/
		leftTime = DFM_WaitUntill(g_CycTick);
		/*- 喂狗 */
		PFM_CFC_WatchDog();
		g_MSCP_BirthCount++;
		MSCP_LOG_MSG("-----MSCP_BirthCount:%d,M/S:0x%x--Partner:0x%x,N/D:%d/%d-err_cut:%d,err_cyc:%d,apperr_cut:%d,apperr_cyc:%d---version:%d.%d.%d.%d\n",
			g_MSCP_BirthCount,SFM_2x2_GetLocal2x2State(),SFM_2x2_GetPartner2x2State(),
			MSCP_Get_AutoRbootCut(),g_PFM_Cfg.M_AutoReboot_Count,
			s_2oo2_Ctrl.FrameCtrl.err_cut,s_2oo2_Ctrl.FrameCtrl.err_cyc,
			s_2oo2_Ctrl_App.FrameCtrl.err_cut,s_2oo2_Ctrl_App.FrameCtrl.err_cyc,
			MSCP_SW_VERION[0], MSCP_SW_VERION[1], MSCP_SW_VERION[2], MSCP_SW_VERION[3]);
		DFM_Drv_CycLog();
		/*TODO 发送2x状态起始信号量*/
		SFM_2x2_Thread_PostStart();
		PFM_CFC_Check(24);
		/*- @alias 2oo2周期校时 */
		if (0x55u == g_PFM_Cfg.M_2oo2_Enable)
		{
			MSCP_LOG_MSG("2oo2start time left:%lld us\n",leftTime);
			costlog[0] = SFM_2oo2_Sync(&offset_2oo2);
		}
		else
		{
			costlog[0] = CM_GetTick();
		}
		PFM_CFC_Check(25);
		/*- @alias 2x2周期校时 */
		if (0x55u == g_PFM_Cfg.M_2x2_Enable)
		{
			MSCP_LOG_MSG("2x2start\n");
			SFM_2x2_Sync(g_CycTick, &offset_2x2);
		}
		else
		{
			/* 无处理 */
		}
		costlog[1] = CM_GetTick();
/**************↑↑↑↑↑禁止添加代码，包括打印！***************/
		delayTime = (CM_INT32)CM_UNSIGNED_LONG_INT_EXP((costlog[0] - g_CycTick) / 1000u);
		MSCP_LOG_MSG("2oo2 sync delay = %d us\n", delayTime);
		MSCP_LOG_MSG("2x2 sync delay = %lld us\n", (costlog[1] - costlog[0]) / 1000u);
		MSCP_LOG_MSG("BASE_CYC_CTRL_SYNC = %lld us\n", NOW_USED_TIME);
/*- ***********数据输入阶段*/
		/*#############输入微周期#############*/
		/*- 输入微周期：输入数据处理 */
		costlog[2] = CM_GetTick();
		PFM_InputProc();
		MSCP_LOG_MSG("BASE_INPUT_RCV = %lld us\n", NOW_USED_TIME);
/*- ***********输入数据处理阶段*/
		/*- 处理微周期：协议层解析 */
		/*协议层解析*/
		SFM_UnPrtclProc();
		MSCP_LOG_MSG("timecurr 6 Input UnPrtclProc = %lld us\n", NOW_USED_TIME);
		costlog[3] = CM_GetTick();
		/*计算输入阶段耗时，并通过暗文日志发送*/
		darkInPutTime = (CM_UINT32)CM_UNSIGNED_LONG_INT_EXP((costlog[3] - costlog[2]) / 1000u);
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_INPUTTIME, 4U, &darkInPutTime);
		MSCP_LOG_MSG("BASE_INPUT_PROCESS = %lld us\n", NOW_USED_TIME);

/*- ***********等待APP结束阶段*/
		/*#############等待应用结束#############*/
		/*- @alias 等待应用完成信号 */
		PFM_CFC_Check(47);
		for (i = 1; i <= g_PFM_Cfg.app_num; i++)
		{
			if(NULL == s_appCtrl[i].pAppfunc)
			{
				/*- 无处理 */
			}
			else
			{
				rt = CM_Sem_Wait(s_appCtrl[i].m_appStop);
				/*计算应用实际耗时，并通过暗文日志发送*/
				MSCP_LOG_MSG("app%d run time %lld us\n",i,(s_appCtrl[i].m_appStop_Time - s_appCtrl[i].m_appStart_Time)/1000u);
				tempAppTimeBuf[i-1] = (CM_UINT32)CM_UNSIGNED_LONG_INT_EXP((s_appCtrl[i].m_appStop_Time - s_appCtrl[i].m_appStart_Time)/1000u);
				CM_LongToChar(tempAppTimeBuf[i-1],darkAppTimeBuf+4*i-4);
				CM_RE_ASSERT((s_appCtrl[i].m_appStop_Time - s_appCtrl[i].m_appStart_Time) <= u_64temp, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_4);
				CM_RE_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_3);
			}
		}
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_APPTIME, 20U, &darkAppTimeBuf[0]);
#ifdef QNX
		(void)trace_nlogf(123 , 0,"app_end");
#endif
		MSCP_LOG_MSG("timecurr 7 Wait AppEnd = %lld us\n", NOW_USED_TIME);

		/*- ***********自检阶段*/
		/*- 发送自检开始信号量 */
		selfCheckSemPost();
		/*- 等待自检结束信号量 */
		selfCheckSemWait();
		MSCP_LOG_MSG("timecurr 8 SelfCheck = %lld us\n", NOW_USED_TIME);

/*- ***********APP数据跟随阶段*/
		costlog[4] = CM_GetTick();
		PFM_EndProc();
		costlog[5] = CM_GetTick();

		/*计算周期末耗时，并通过暗文日志发送*/
		darkCycEndTime = (CM_UINT32)CM_UNSIGNED_LONG_INT_EXP((costlog[5] - costlog[4]) / 1000u);
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_ENDTIME, 4U, &darkCycEndTime);
		MSCP_LOG_MSG("timecurr 10 PFM_EndProc End = %lld us\n", NOW_USED_TIME);
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_2OO2, 1U, &state);
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_2x2, 1U, &state);

		SFM_LogOutPrtcl();
    }
    return NULL;
}

/**
* @brief 应用任务
* @details
* 本任务阻塞等待来自平台任务的启动信号
* 收到启动信号后执行一次应用任务
* 应用任务执行完成后向平台任务反馈结束信号
*/
static CM_THREAD_FUNC_T MSCP_CycApp(IN CM_Thread_Arg_Struct_T* arg)
{
    /*- 变量初始化 */
	ENUM_CM_RETURN rt = ENUM_CM_FALSE;
    STRU_APP_CTRL_T* pCtrl = (STRU_APP_CTRL_T*)arg;
#if QNX
    (void)ThreadCtl(_NTO_TCTL_RUNMASK, pCtrl->p_core_mask);
#endif
    /*- 循环执行任务逻辑 */
    while (1)
    {
        /*- 等待来自平台任务的启动信号 */

    	rt = CM_Sem_Wait(pCtrl->m_appStart);
    	CM_RE_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_1);
    	pCtrl->m_appStop_Time = 0u;
    	pCtrl->m_appStart_Time = CM_GetTick();
        /*- 逻辑处理微周期 */
        s_LogicProc(pCtrl->pAppfunc);
        pCtrl->m_appStop_Time = CM_GetTick();
        /*- 向平台任务反馈任务完成信号 */
        rt = CM_Sem_Post(pCtrl->m_appStop);
        MSCP_LOG_MSG("app run time %d us\n",(pCtrl->m_appStop_Time - pCtrl->m_appStart_Time)/1000u);
        CM_RE_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_2);
    }
    return NULL;
}

/**
* @brief 应用调度初始化
* @details
* 初始话应用调度的配置信息STRU_APP_CTRL_T，
* 含应用函数入口、启动停止信号量等。
*/
static void s_appCtrlInit(void)
{
    /*- 变量初始化 */
    CM_INT32 i = 0;
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;
    CM_BOOL rtCheck = CM_FALSE;
    CM_CHAR appName[32] = {0}; /* 主键值 */

    /*- 初始化应用函数入口和绑定的CPU内核 前两个Main是大核A72*/
    s_appCtrl[1].pAppfunc = g_APP_FUNC_SET.pApp1;
    s_appCtrl[1].p_core_mask = (void*)0x20;

    s_appCtrl[2].pAppfunc = g_APP_FUNC_SET.pApp2;
    s_appCtrl[2].p_core_mask = (void*)0x10;

    s_appCtrl[3].pAppfunc = g_APP_FUNC_SET.pApp3;
    s_appCtrl[3].p_core_mask = (void*)0x08;

    s_appCtrl[4].pAppfunc = g_APP_FUNC_SET.pApp4;
    s_appCtrl[4].p_core_mask = (void*)0x04;

    s_appCtrl[5].pAppfunc = g_APP_FUNC_SET.pApp5;
    s_appCtrl[5].p_core_mask = (void*)0x02;

    /*- 初始化应用启动、停止信号量 */
    for (i = 1; i <= g_PFM_Cfg.app_num; i++)
    {
        if(NULL == s_appCtrl[i].pAppfunc)
    	{
    		MSCP_LOG_MSG("s_appCtrl[%d].pAppfunc is NULL!\n", i);
		}
		else
		{
			rt = CM_Sem_Init(&s_appCtrl[i].m_appStart);
			CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_1);
			
			rt = CM_Sem_Init(&s_appCtrl[i].m_appStop);
			CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_2);
		}
    }

    /*- 创建应用线程 */
    for (i = 1; i <= g_PFM_Cfg.app_num; i++)
    {	
    	if(s_appCtrl[i].pAppfunc== NULL )
    	{
    		MSCP_LOG_MSG("s_appCtrl[%d].pAppfunc is NULL!\n", i);
		}
		else
		{
            CM_ASSERT(NULL != appName, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_3);
			(void)snprintf(appName, sizeof(appName), "app%d", i);
	    	rtCheck = CM_Thread_Create((CM_THREAD_T*)NULL, (CM_THREAD_FUNC_T)MSCP_CycApp, appName, 0, CM_TASK_PRIORITY_73, (CM_Thread_Arg_Struct_T*)(&s_appCtrl[i]));
	    	CM_ASSERT(CM_TRUE == rtCheck, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_4);
	        CM_Sleep(100u); /* 延时等待任务创建 */
		}
    }
}

/**
* @brief 自检初始化
*/
static void SelfCheckInit(void)
{
#ifdef QNX
    /*- 文件自检初始化 */
    //PFM_FileInit();
	/*- 内存自检初始化*/
    PFM_MemCheck_Init();
	/*- CPU自检初始化*/
	s_CpuCheckCtrlInit();
#endif/*QNX*/

	/*- 自检主线程初始化*/
	s_SelfCheckCtrlInit();
	/*硬件自检*/
	PFM_BoardCheck_TolerateThreetimes();
	selfCheckSemPost();
	selfCheckSemWait();
    /*- 是否开启2x2功能 */
    if (0x55u == g_PFM_Cfg.M_2x2_Enable)
    {
		/*- 串口自检*/
		PFM_UartComCheck();
    }
    else
    {
    	;
    }

}

/**
* @brief 自检信号量等待
*/
static void selfCheckSemWait(void)
{
#ifdef QNX
    /*- 变量初始化 */
    CM_INT32 i = 0;
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;

    /*- 初始化应用启动、停止信号量 */
    for (i = 1; i <= 6; i++)
    {
    	rt = CM_Sem_Wait(s_CpuCheckCtrl[i].selfCheck.m_selfCheckStop);
    	CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_1);
    }
    rt = CM_Sem_Wait(s_selfCheck_Ctrl.m_selfCheckStop);
    CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_2);
#endif
}

/**
* @brief 自检信号量释放
*/
static void selfCheckSemPost(void)
{
#ifdef QNX
    /*- 变量初始化 */
    CM_INT32 i = 0;
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;

    /*- 初始化应用启动、停止信号量 */
    rt = CM_Sem_Post(s_selfCheck_Ctrl.m_selfCheckStart);
    CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_7, TSCP_DARK_ASSERT_1);
    for (i = 1; i <= 6; i++)
    {
    	rt = CM_Sem_Post(s_CpuCheckCtrl[i].selfCheck.m_selfCheckStart);
    	CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_7, TSCP_DARK_ASSERT_2);
    }

#endif
}

/**
* @brief CPU自检初始化
*/
static void s_CpuCheckCtrlInit(void)
{
    /*- 变量初始化 */
    CM_INT32 i = 0;
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;
    CM_BOOL checkRt = CM_FALSE;
    /*- 初始化应用启动、停止信号量 */
    for (i = 1; i <= 6; i++)
    {
        rt = CM_Sem_Init(&s_CpuCheckCtrl[i].selfCheck.m_selfCheckStart);
        CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_8, TSCP_DARK_ASSERT_1);
        rt = CM_Sem_Init(&s_CpuCheckCtrl[i].selfCheck.m_selfCheckStop);
        CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_8, TSCP_DARK_ASSERT_2);
    }

    s_CpuCheckCtrl[1].p_core_mask = (void*)0x20;

    s_CpuCheckCtrl[2].p_core_mask = (void*)0x10;

    s_CpuCheckCtrl[3].p_core_mask = (void*)0x08;

    s_CpuCheckCtrl[4].p_core_mask = (void*)0x04;

    s_CpuCheckCtrl[5].p_core_mask = (void*)0x02;

    s_CpuCheckCtrl[6].p_core_mask = (void*)0x01;
    /*- 创建应用线程 */
    for (i = 1; i <= 6; i++)
    {
    	checkRt = CM_Thread_Create((CM_THREAD_T*)NULL, (CM_THREAD_FUNC_T)MSCP_CheckPeer, "CpuCheck", 0, CM_TASK_PRIORITY_73, (CM_Thread_Arg_Struct_T*)(&s_CpuCheckCtrl[i]));
    	CM_ASSERT(CM_TRUE == checkRt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_8, TSCP_DARK_ASSERT_3);
        CM_Sleep(100u); /* 延时等待任务创建 */
        /*MSCP_LOG_MSG("cpu[%d]_Check_Thread_Create \r\n", i); */
    }
}

/**
* @brief 自检线程初始化
*/
static void s_SelfCheckCtrlInit(void)
{
	/*- 变量初始化 */
	ENUM_CM_RETURN rt = ENUM_CM_FALSE;
	CM_BOOL checkRt = CM_FALSE;

	rt = CM_Sem_Init(&s_selfCheck_Ctrl.m_selfCheckStart);
	CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_9, TSCP_DARK_ASSERT_1);
	rt = CM_Sem_Init(&s_selfCheck_Ctrl.m_selfCheckStop);
	CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_9, TSCP_DARK_ASSERT_2);
	checkRt = CM_Thread_Create((CM_THREAD_T*)NULL, (CM_THREAD_FUNC_T)MSCP_CheckMain, "selfcheck", 0, CM_TASK_PRIORITY_73, (CM_Thread_Arg_Struct_T*)(&s_selfCheck_Ctrl));
	CM_ASSERT(CM_TRUE == checkRt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_9, TSCP_DARK_ASSERT_3);
    CM_Sleep(100u); /* 延时等待任务创建 */
}
/**
* @brief 主自检线程
* @details 包括CPU周期自检和内存周期自检
*/
static CM_THREAD_FUNC_T MSCP_CheckMain(IN CM_Thread_Arg_Struct_T* arg)
{
	/*无需锁定内核，在app空闲时调用*/
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;
    /*- 变量初始化 */
	STRU_SELF_CHECK_CTRL_T* pCtrl = (STRU_SELF_CHECK_CTRL_T*)arg;
	CM_UINT64 costlog[10] = {0u};	/* 记录耗时变量 */
    /*- 自检线程主循环 */
    while (1)
    {
        /*- 接收自检开始信号 */
    	rt = CM_Sem_Wait(pCtrl->m_selfCheckStart);
    	CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_1);
        /*- 内存自检 */
        costlog[0] = CM_GetTick();
    	PFM_MemCheck();
    	costlog[1] = CM_GetTick();
        MSCP_LOG_MSG("cyc MemCheck cost = %d us\n", (costlog[1] - costlog[0]) / 1000u);
        /*- 板卡自检*/
        PFM_BoardCheck();
        costlog[2] = CM_GetTick();
        MSCP_LOG_MSG("PFM_BoardCheck cost = %d us\n", (costlog[2] - costlog[1]) / 1000u);
        /*- 发送自检结束信号 */
        MSCP_LOG_MSG("Self_Check_End \r\n");
        rt = CM_Sem_Post(pCtrl->m_selfCheckStop);
        CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_2);
    }

    return NULL;
}

/**
* @brief 从自检线程
* @details 只包括CPU自检
*/
static CM_THREAD_FUNC_T MSCP_CheckPeer(IN CM_Thread_Arg_Struct_T* arg)
{
    /*- 变量初始化 */
	ENUM_CM_RETURN rt = ENUM_CM_FALSE;
	STRU_CPU_SELF_CHECK_CTRL_T* pCtrl = (STRU_CPU_SELF_CHECK_CTRL_T*)arg;
#if QNX
	(void)ThreadCtl(_NTO_TCTL_RUNMASK, pCtrl->p_core_mask);
#endif
    /*- 自检线程主循环 */
    while (1)
    {
        /*- 接收自检开始信号 */
    	rt = CM_Sem_Wait(pCtrl->selfCheck.m_selfCheckStart);
    	CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_11, TSCP_DARK_ASSERT_1);
        /*- CPU自检 */
    	PFM_CPUCheck();
        /*- 发送自检结束信号 */
    	rt = CM_Sem_Post(pCtrl->selfCheck.m_selfCheckStop);
    	CM_ASSERT(ENUM_CM_TRUE == rt, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_11, TSCP_DARK_ASSERT_2);
    }
    return NULL;
}

/**
* @brief 逻辑层处理
* @details 根据当前热备状态确定是否调用应用周期逻辑
*/
static void s_LogicProc(ENUM_CM_RETURN(*pAppfunc)(void))
{
    /*- 变量初始化 */
    ENUM_CM_RETURN ret = ENUM_CM_FALSE;
    ENUM_2x2_STATE_T localState = SFM_2x2_GetLocal2x2State();
    

    /*- 是否关闭了2x2功能 */
    if (0xAAu == g_PFM_Cfg.M_2x2_Enable)
    {
    	/*- 本系默认为主 */
        localState = ENUM_2x2_MASTER;
    }
    else
    {
    	/*- 无处理 */
    }

    /*MSCP_LOG_MSG("STAT:%s\n", s_2x2stat_str[localState]);*/
    /*- 本系热备状态 */
    switch (localState)
    {
    case ENUM_2x2_SHUTDOWN: /*-< 宕机 */
        /*- 什么都不做*/
        /*- 返回 */
        break;
    case ENUM_2x2_OFFLINE: /*-< 离线 */
        /*- 执行周期逻辑(但不会被输出) */
        ret = (*pAppfunc)();
        /*- 返回 */
        break;
    case ENUM_2x2_PRE_MASTER: /*-< 预升主 */
        /*- 执行周期逻辑(但不会被输出) */
        ret = (*pAppfunc)();
        /*- 返回 */
        break;
    case ENUM_2x2_MASTER: /*-< 主系 */
        /*- 执行周期逻辑(会被输出) */
        ret = (*pAppfunc)();
        /*- 返回 */
        break;
    case ENUM_2x2_SLAVE:/*-< 备系 */
        /*- 执行应用周期逻辑(但不会被输出) */
        ret = (*pAppfunc)();
        /*- 返回 */
        break;
    default:
        /*- 返回 */
        break;
    }

    /*- 如果应用返回错误 */
    if(ENUM_CM_FALSE == ret)
    {
    	/*- 宕机并执行自动重启 */
    	CM_RE_ASSERT(0, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_12, TSCP_DARK_ASSERT_1);
    }
    /*- 如果应用返回未知 */
    else if(ENUM_CM_NULL == ret)
    {
    	/*- 宕机 */
    	CM_ASSERT(0, MAIN_MODE, DARK_FAULT_CODE_FUN_ORDER_12, TSCP_DARK_ASSERT_2);
    }
    else
    {
    	/*- 无处理  */
    }
}
