/**
* @file SFM_2oo2.c
* @brief Safe Function Module:2x2功能
* @details
* 2x2上电初始化：初始化、上电同步、比较
* 输入阶段和输出阶段的双机热备处理
* @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 "SFM_2x2.h"
#include "CM_Convert.h"
#include "CM_Memory.h"
#include "CM_CRC32.h"
#include "CM_Time.h"
#include "CM_RingBuf.h"
#include "DFM_Time.h"
#include "CFM_Net.h"
#include "SFM_2oo2.h"
#include "SFM_Prtcl.h"
#include "SFM_package.h"
#include "PFM_Cfg.h"
#include "PFM_Log.h"
#include "PFM_ControlFlowCheck.h"
#include "DFM_DRV.h"
#include "PFM_SelfCheck.h"
#include "stdarg.h"

/*通信中断时间和同步超时时间可以相同，此时优先执行通信中断切系*/

CM_INT32 g_2x2oo2_base = 0;          /**< 2x2oo2双缓冲区的平台索引 */
CM_INT32 g_2x2oo2_data_num = 0;      /**< 2x2oo2的通道总数 */
STRU_2x2oo2_rx_T g_2x2oo2_rx[2][24]; /**< 2x2oo2的接收双缓冲区 */
STRU_2x2oo2_tx_T g_2x2oo2_tx[2][24]; /**< 2x2oo2的发送双缓冲区 */
CM_UINT8 g_2x2RcvMaxNum[2] = {0};	 /**< 2x2双缓冲区接收最大序号*/

/*
2x2通信帧格式：
4字节 长度（不含自身）
4字节 源ID
4字节 目的ID
4字节 周期号
4字节 序列号
1字节 类型
2字节 帧总数
2字节 帧序号
n字节 数据
4字节 CRC
*/

CM_UINT32 g_MSCP_SysCount; /**< 系统周期号 */

static CM_INT32 g_RxBaseFollow_len = 0;               /**< 收到的平台跟随数据长度 */
static CM_UINT8 g_RxBaseFollow[SFM_FOLLOW_BUFF_SIZE]; /**< 收到的平台跟随数据报文 */
static CM_INT32 g_TxBaseFollow_len = 0;               /**< 发送的平台跟随数据长度 */
static CM_UINT8 g_TxBaseFollow[SFM_FOLLOW_BUFF_SIZE]; /**< 发送的平台跟随数据报文 */
/*4字节长度+m字节协议同步数据+4字节长度+n字节平台跟随数据*/

static CM_INT32 g_RxAppFollow_len = 0;               /**< 收到的应用跟随数据长度 */
static CM_UINT8 g_RxAppFollow[MSCP_FOLLOW_BUFF_SIZE*2]; /**< 收到的应用跟随数据报文 */
static CM_INT32 g_RxAppFollowCrc_len = 0;               /**< 收到的应用跟随数据长度 */
static CM_UINT8 g_RxAppFollowCrc[12]; /**< 收到的应用跟随数据报文 */
CM_INT32 g_TxAppFollow_len = 0;               /**< 发送的应用跟随数据长度 */
CM_UINT8 g_TxAppFollow[MSCP_FOLLOW_BUFF_SIZE*2]; /**< 发送的应用跟随数据报文 */

#define SFM_2x2_TM_RING_SIZE (10)  /**< 2x2时钟同步累计的周期数 */
#define SFM_2x2_TM_FIX_VAL (10)     /**< 最小调整偏差 */
static STRU_CM_RING_T s_2x2_TmRing; /**< 2x2时钟同步数据 */
static STRU_2X2_CTRL_T 			s_2x2_Ctrl; 	  /**< 主线程2x2控制 */
static STRU_2X2_STATE_CTRL_T 	s_2x2_state_Ctrl; /**< 子线程2x2状态控制 */
STRU_2X2_STATE_THRRAD_T  s_2x2_thread_Ctrl;/**< 子线程2x2参数 */

static CM_UINT8 s_2x2_Cache[NET_UDP_BUF_SIZE];  /**< 2x2通信缓冲区 */
static CM_UINT8 s_2x2_InputIoState[40] = {0};

static CM_UINT32 s_2x2_TxSyncLen;      /**< 发送2x2同步报文长度 */
static CM_UINT8 s_2x2_TxSyncMsg[1000]; /**< 发送2x2同步报文 */

static CM_INT32 s_2x2_RxSyncLen;       /**< 接收2x2同步报文长度 */
static CM_UINT8 s_2x2_RxSyncMsg[1000]; /**< 接收2x2同步报文 */
static CM_UINT64 s_2x2_RxSyncTick;     /**< 接收2x2同步报文时刻 */

static void s_State_Switch(void);
/*2x交互前的系内热备状态同步*/
static void s_State_2xBefore_2oo2Sync(STRU_2OO2_NET_NO_PACK_T *p_2oo2_Ctrl,OUT STRU_2X2_STATE_CTRL_T *p_peer_state);
/*2x交互后的系内热备状态同步*/
static void s_State_2xAfter_2oo2Sync(STRU_2OO2_NET_NO_PACK_T *p_2oo2_Ctrl,OUT STRU_2X2_STATE_CTRL_T *p_peer_state);
/*2x通信解析*/
static CM_BOOL s_State_2x2_Analysis(OUT STRU_2X2_STATE_CTRL_T *p_partner_state,CM_UINT8 *recvbuf,CM_INT32 len);
/*2x状态同步*/
static ENUM_CM_RETURN s_State_2x2Sync(OUT STRU_2X2_STATE_CTRL_T *p_partner_state);
static void s_State_Transition(void);
/**
 * @brief 输入阶段,主系发送平台跟随数据前的2oo2比较
 */
static void s_2x2_BaseFollow_2oo2Check_Send(void);
/**
 * @brief 输入阶段，非主系进行相关CRC校验后跟随
 */
static void s_2x2_BaseFollow_Sync(void);
/**
 * @brief 周期末阶段，备系接收主系应用跟随CRC后的比较逻辑
 */
static void s_2x2_AppFollow_SyncCheck(void);
/**
 * @brief 输出阶段，备系接收主系输出数据CRC后的比较逻辑
 */
static void s_2x2_Output_SyncCheck(IN const CM_UINT8 *CheckBuf, CM_INT32 CheckLen);

/**
 * 统一置切系标志
 */
static void s_2x2_CloseSwitchFlag(void);
/**
* @brief 2X状态切换独立线程
*/
static CM_THREAD_FUNC_T  SFM_2x2_StateChange_Thread(void);
/**
* @brief 平台记录格式化字符串日志
* @param filename 文件路径
* @param func 函数名
* @param line 行号
* @param fmt 格式化字符串
*/
static void SFM_2x2_LOG_MSG(IN const CM_CHAR *filename,  IN CM_INT32 line, IN const CM_CHAR* fmt, ...);
#define SFM_LOG_MSG_2X(fmt, ...) (SFM_2x2_LOG_MSG(FILENAME(__FILE__),(CM_INT32)__LINE__,(fmt), ##__VA_ARGS__))
/* 接收2x2报文 */
static void s_2x2_Recv(void);
/* 系内同步2x2状态 */
static void s_Ctrl_2oo2Sync(OUT STRU_2X2_CTRL_T *pPeerCtrl);
/* 系内同步2x2输入数据 */
static void SFM_2x2_Input2oo2Exchange(STRU_2X2_CTRL_T *peerCtrl);
/* 判断2x422以及以太网的通信状况并且填写暗文日志  */
static void SFM_2x2_Eth422StateDark(void);

/* 输入周期号同步函数 */
static void SFM_2x2_InputSysCycSyn(STRU_2X2_CTRL_T *peerCtrl){
    if(s_2x2_Ctrl.RxInputSysCyc > peerCtrl->RxInputSysCyc)
    {
    	/*- 更新临机输入同步周期号*/
    	peerCtrl->RxInputSysCyc = s_2x2_Ctrl.RxInputSysCyc;
    }
    else if(s_2x2_Ctrl.RxInputSysCyc < peerCtrl->RxInputSysCyc)
    {
    	/*- 更新本机输入同步周期号*/
    	s_2x2_Ctrl.RxInputSysCyc = peerCtrl->RxInputSysCyc;
    }
    else
    {
    	/*- 周期号相同 不做修改*/;
    }
}

/* 跟随数据同步*/
static CM_INT32 SFM_2x2_BaseFollowSyn(STRU_2X2_CTRL_T *peerCtrl){
	CM_INT32 ret = 0;
    if (s_2x2_Ctrl.RxBaseFollowSysCyc > peerCtrl->RxBaseFollowSysCyc)
    {
        /*需要向邻机发送跟随数据*/
        ret = SFM_2oo2_Exchange_Currency(g_RxBaseFollow, g_RxBaseFollow_len, g_RxBaseFollow, (CM_UINT32)0, ENUM_2oo2_INPUT_EX);/*通过输入"0"防止g_RxFollow被修改*/
    }
    else if (s_2x2_Ctrl.RxBaseFollowSysCyc < peerCtrl->RxBaseFollowSysCyc)
    {
        /*需要从邻机接收跟随数据*/
        g_RxBaseFollow_len = SFM_2oo2_Exchange_Currency(g_RxBaseFollow, (CM_INT32)0, g_RxBaseFollow, (CM_UINT32)sizeof(g_RxBaseFollow), ENUM_2oo2_INPUT_EX);/*通过输入"0"实现只收不发*/
        s_2x2_Ctrl.RxBaseFollowSysCyc = peerCtrl->RxBaseFollowSysCyc;
    }
    else
    {
        /* 无需处理 */
    }
    return ret;
}

/**
* @brief 切系按钮监督
* @return 无
* @details
* 用于监督切系按钮是否被按下3s
*/
static void s_State_Switch(void)
{
	/*- 变量初始化 */
	static CM_UINT64 s_timeFirst = 0u;
	static CM_UINT64 s_timeSecond = 0u;
	static CM_BOOL s_timeFlag = CM_FALSE;
	static ENUM_2x2_STATE_T s_LocalState;  	   /**< 本系热备状态，2oo2比较 */
	static ENUM_2x2_STATE_T s_PartnerState;     /**< 收到的对系热备状态，2oo2交换 */
	CM_INT32 ret = 0;

	if((((ENUM_2x2_MASTER == s_2x2_state_Ctrl.LocalState) && (ENUM_2x2_SLAVE == s_2x2_state_Ctrl.PartnerState)) ||
		((ENUM_2x2_SLAVE == s_2x2_state_Ctrl.LocalState) && (ENUM_2x2_MASTER == s_2x2_state_Ctrl.PartnerState))) &&
		((ENUM_2x2_SWITCH_CLOSE == s_2x2_state_Ctrl.LocalSwitchState)) && (s_timeFlag == CM_FALSE))
	{
		/*- 判断是否连续3s按住切系按钮*/
		ret = DFM_switchButton();
		if(1 == ret)
		{
			/*- 记录第一次按下的时间*/
			s_timeFirst = CM_GetTick();
			s_timeFlag = CM_TRUE;
			/*更新切系参数*/
			s_LocalState = s_2x2_state_Ctrl.LocalState;
			s_PartnerState = s_2x2_state_Ctrl.PartnerState;
		}
		else
		{
			s_timeFlag = CM_FALSE;
		}
	}
	else
	{
		/*持续按钮检测*/
		if(s_timeFlag == CM_TRUE)
		{
			/*- 获取按钮按下结果*/
			ret = DFM_switchButton();
			/*- 如果按下记录档次按下时间，如果未按下跳出监督*/
			if(1 == ret)
			{
				s_timeSecond = CM_GetTick();
				/*- 当次按下时间距第一次按下时间相差3s,则判断是否需要切系 */
				if((s_timeSecond - s_timeFirst) >= MSCP_2X2_SWITCH_3S)
				{
					/*- 如果未切系则准备切系,如果以切系则休眠后继续等待松开按钮,防止持续按压 */
					if((s_LocalState == s_2x2_state_Ctrl.LocalState) && (s_PartnerState == s_2x2_state_Ctrl.PartnerState))
					{
						s_2x2_state_Ctrl.LocalSwitchState = ENUM_2x2_SWITCH_OPEN;
					}
					else
					{
						s_2x2_state_Ctrl.LocalSwitchState = ENUM_2x2_SWITCH_CLOSE;
					}
				}
				else
				{
					s_2x2_state_Ctrl.LocalSwitchState = ENUM_2x2_SWITCH_CLOSE;
				}
			}
			else
			{
				s_timeFlag = CM_FALSE;
				/* 实际无需清空time变量,导向安全侧则清空 */
				s_timeFirst = 0u;
				s_timeSecond = 0u;
				s_2x2_state_Ctrl.LocalSwitchState = ENUM_2x2_SWITCH_CLOSE;
			}
		}
		else
		{
			 (void)DFM_switchButton();
		}
	}

}
/**
* @brief 2x交互前的系内热备状态同步
* @param pPeerCtrl 邻机热备信息
* details
* 系内交换热备信息；
* 校验2oo2双机的热备状态是否一致；
* 系内同步对系连接状态；
* 系内同步收到的状态帧信息。
*/
static void s_State_2xBefore_2oo2Sync(STRU_2OO2_NET_NO_PACK_T *p_2oo2_Ctrl,OUT STRU_2X2_STATE_CTRL_T *p_peer_state)
{
	/*- 变量初始化 */
	CM_INT32 	rcvlen = -1;
    ENUM_CM_RETURN retError = ENUM_CM_FALSE;
    /*- 入参检查 */
    CM_ASSERT(NULL != p_peer_state, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_1);

    /*- 系内交换热备状态信息 */
	retError = CM_Memset(p_peer_state, (CM_UINT8)0, sizeof(STRU_2X2_STATE_CTRL_T), sizeof(STRU_2X2_STATE_CTRL_T));
	CM_RE_ASSERT(ENUM_CM_TRUE == retError, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_2);
	/*二取本机热备状态、按钮状态、通信状态等、确保双CPU数据一致*/
	rcvlen = CFM_2oo2_Currency_NoSplit(p_2oo2_Ctrl,(CM_UINT8*)&s_2x2_state_Ctrl,sizeof(STRU_2X2_STATE_CTRL_T),(CM_UINT8*)p_peer_state,sizeof(STRU_2X2_STATE_CTRL_T));

	CM_RE_ASSERT(rcvlen == sizeof(STRU_2X2_STATE_CTRL_T), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_3);

    /*- 校验2oo2双机的热备状态是否一致 */
	/* 本地状态*/
    CM_RE_ASSERT(s_2x2_state_Ctrl.LocalState == p_peer_state->LocalState, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_4);
    SFM_LOG_MSG_2X("2oo2:MyoffLineCut  = %d, OtheroffLineCut = %d\n",s_2x2_state_Ctrl.offLineCounter,p_peer_state->offLineCounter);
    CM_RE_ASSERT(s_2x2_state_Ctrl.offLineCounter == p_peer_state->offLineCounter, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_5);
    CM_RE_ASSERT(s_2x2_state_Ctrl.preMasterCounter == p_peer_state->preMasterCounter, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_6);
    /* 本地通信状态，主线程2取同步过*/
    CM_RE_ASSERT(s_2x2_state_Ctrl.LastRxInputSysCyc == p_peer_state->LastRxInputSysCyc, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_7);
    CM_RE_ASSERT(s_2x2_state_Ctrl.LastFollowCyc == p_peer_state->LastFollowCyc, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_8);
    CM_RE_ASSERT(s_2x2_state_Ctrl.LastCheckOKCount == p_peer_state->LastCheckOKCount, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_10);
    CM_RE_ASSERT(s_2x2_state_Ctrl.LastLocalState == p_peer_state->LastLocalState, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_11);
    CM_RE_ASSERT(s_2x2_state_Ctrl.LastPartnerState == p_peer_state->LastPartnerState, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_12);
    CM_RE_ASSERT(s_2x2_state_Ctrl.OutPutCheckFailFlag == p_peer_state->OutPutCheckFailFlag, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_13);
    CM_RE_ASSERT(s_2x2_state_Ctrl.AppFollowCmpFlag == p_peer_state->AppFollowCmpFlag,SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_17, TSCP_DARK_ASSERT_14);

    /*同步按钮状态*/
    s_2x2_state_Ctrl.PeerSwitchState = p_peer_state->LocalSwitchState;
    s_2x2_state_Ctrl.PeerAIDSwitchState = p_peer_state->LocalAIDSwitchState;
    /*同步输入IO*/
    (void)CM_Memcpy(s_2x2_state_Ctrl.PeerInputIoState,10,p_peer_state->MineInputIoState,10);
}
/**
* @brief 系内热备状态同步
* @param pPeerCtrl 邻机热备信息
* details
* 系内交换热备信息；
* 校验2oo2双机的热备状态是否一致；
* 系内同步对系连接状态；
* 系内同步收到的状态帧信息。
*/
static void s_State_2xAfter_2oo2Sync(STRU_2OO2_NET_NO_PACK_T *p_2oo2_Ctrl,OUT STRU_2X2_STATE_CTRL_T *p_peer_state)
{
	/*- 变量初始化 */
	CM_INT32 	rcvlen = -1;
	CM_UINT8 i = 0u;
    ENUM_CM_RETURN retError = ENUM_CM_FALSE;
    /*- 入参检查 */
    CM_ASSERT(NULL != p_peer_state, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_18, TSCP_DARK_ASSERT_1);

    /*- 系内交换热备状态信息 */
	retError = CM_Memset(p_peer_state, (CM_UINT8)0, sizeof(STRU_2X2_STATE_CTRL_T), sizeof(STRU_2X2_STATE_CTRL_T));
	CM_RE_ASSERT(ENUM_CM_TRUE == retError, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_18, TSCP_DARK_ASSERT_2);
	/*二取本机热备状态、按钮状态、通信状态等、确保双CPU数据一致*/
	rcvlen = CFM_2oo2_Currency_NoSplit(p_2oo2_Ctrl,(CM_UINT8*)&s_2x2_state_Ctrl,sizeof(STRU_2X2_STATE_CTRL_T),(CM_UINT8*)p_peer_state,sizeof(STRU_2X2_STATE_CTRL_T));
	CM_RE_ASSERT(rcvlen == sizeof(STRU_2X2_STATE_CTRL_T), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_18, TSCP_DARK_ASSERT_3);

    /*- 系内同步对系连接状态 */
    for(i = 0u;i <= MSCP_2X2_COM_THIS_STATE_NUM;i++)
    {
    	s_2x2_state_Ctrl.PeerComOKCount[i] = p_peer_state->MineComOKCount[i];
    	s_2x2_state_Ctrl.PeerUartOKCount[i] = p_peer_state->MineUartOKCount[i];
    }

    /*- @alias 系内同步收到的状态帧 */
    if((s_2x2_state_Ctrl.RxStateSysCyc < p_peer_state->RxStateSysCyc) ||
      ((s_2x2_state_Ctrl.RxStateSysCyc == p_peer_state->RxStateSysCyc) && (s_2x2_state_Ctrl.RxStateMicroCyc < p_peer_state->RxStateMicroCyc)))
    {
    	/*更新周期号与对系状态*/
    	s_2x2_state_Ctrl.RxStateMicroCyc 	= p_peer_state->RxStateMicroCyc;
    	s_2x2_state_Ctrl.RxStateSysCyc 		= p_peer_state->RxStateSysCyc;
    	s_2x2_state_Ctrl.PartnerState 		= p_peer_state->PartnerState;
    	s_2x2_state_Ctrl.LastPartnerState = p_peer_state->LastPartnerState;
		/*更新对系所有切系状态*/
		s_2x2_state_Ctrl.PartnerSwitchState 	= p_peer_state->PartnerSwitchState;
		s_2x2_state_Ctrl.PartPeerSwitchState 	= p_peer_state->PartPeerSwitchState;
		s_2x2_state_Ctrl.PartnerAIDSwitchState 	= p_peer_state->PartnerAIDSwitchState;
		s_2x2_state_Ctrl.PartPeerAIDSwitchState = p_peer_state->PartPeerAIDSwitchState;
		/*更新对系IO状态*/
		(void)CM_Memcpy(s_2x2_state_Ctrl.RmtMineInputIoState,10,p_peer_state->RmtMineInputIoState,10);
		(void)CM_Memcpy(s_2x2_state_Ctrl.RmtPeerInputIoState,10,p_peer_state->RmtPeerInputIoState,10);
    	SFM_LOG_MSG_2X("2oo2:RxStateSysCyc is small!\n");
    	s_2x2_state_Ctrl.RxSN = p_peer_state->RxSN;
    }
    else
	{
		/*- 无处理 */
	}
    /*时间同步标志*/
    if(s_2x2_state_Ctrl.TimeSyncFlag != p_peer_state->TimeSyncFlag)
    {
    	s_2x2_state_Ctrl.TimeSyncFlag = CM_FALSE;
    	SFM_LOG_MSG_2X("2oo2:TimeSyncFlag is not sync!\n");
    }

    /*判断切系状态*/
    if((ENUM_2x2_SWITCH_OPEN == s_2x2_state_Ctrl.LocalSwitchState) &&
       (ENUM_2x2_SWITCH_OPEN == s_2x2_state_Ctrl.PeerSwitchState) &&
	   (ENUM_2x2_SWITCH_OPEN == s_2x2_state_Ctrl.PartnerSwitchState) &&
       (ENUM_2x2_SWITCH_OPEN == s_2x2_state_Ctrl.PartPeerSwitchState))
    {
    	s_2x2_state_Ctrl.ctrSwitchFlag = 1u;
    	SFM_LOG_MSG_2X("The switch button is effective\n");
    }
    else if((ENUM_2x2_AIDSWITCH_ENABLE == s_2x2_state_Ctrl.LocalAIDSwitchState) &&
    	    (ENUM_2x2_AIDSWITCH_ENABLE == s_2x2_state_Ctrl.PeerAIDSwitchState) &&
    		(ENUM_2x2_AIDSWITCH_ENABLE == s_2x2_state_Ctrl.PartnerAIDSwitchState) &&
    	    (ENUM_2x2_AIDSWITCH_ENABLE == s_2x2_state_Ctrl.PartPeerAIDSwitchState))
    {
    	s_2x2_state_Ctrl.aidSwitchFlag = 1u;
    	SFM_LOG_MSG_2X("The switch AID is effective\n");
    }
    else
    {
    	s_2x2_state_Ctrl.ctrSwitchFlag = 0u;
    	s_2x2_state_Ctrl.aidSwitchFlag = 0u;
    }
}
/**
* @brief 2x热备状态解析
* @param pPeerCtrl 邻机热备信息
* details
* 系内交换热备信息；
* 校验2oo2双机的热备状态是否一致；
* 系内同步对系连接状态；
* 系内同步收到的状态帧信息。
*/
static CM_BOOL s_State_2x2_Analysis(OUT STRU_2X2_STATE_CTRL_T *p_partner_state,CM_UINT8 *recvbuf,CM_INT32 len)
{
	CM_BOOL rtn = CM_FALSE;
	CM_UINT32 msglen = 0;
	CM_UINT32 rcv_offset = 0u;
	CM_UINT32 current_time = (CM_UINT32)(CM_GetTick()/CM_UNSIGNED_MILLION);/*当前时间戳ms*/
	CM_UINT32 time_stamp = CM_LongFromChar(&recvbuf[rcv_offset]);/*接收时间戳ms*/
	rcv_offset = 6;
	msglen = CM_LongFromChar(&recvbuf[rcv_offset]);
	rcv_offset += 4u;
	p_partner_state->LocalID = CM_LongFromChar(&recvbuf[rcv_offset]);
	rcv_offset += 4u;
	p_partner_state->PartnerID = CM_LongFromChar(&recvbuf[rcv_offset]);
	rcv_offset += 4u;
	p_partner_state->TxSN = CM_LongFromChar(&recvbuf[rcv_offset]);
	rcv_offset += 4u;
	p_partner_state->SysCyc = CM_LongFromChar(&recvbuf[rcv_offset]);
	rcv_offset += 4u;
	p_partner_state->MicroCyc = recvbuf[rcv_offset];
	rcv_offset ++;
	p_partner_state->LocalState = CM_LongFromChar(&recvbuf[rcv_offset]);
	rcv_offset += 4u;
	p_partner_state->LastLocalState = CM_LongFromChar(&recvbuf[rcv_offset]);
	rcv_offset += 4u;
	/*解析切系状态*/
	p_partner_state->LocalSwitchState = recvbuf[rcv_offset++];
	p_partner_state->PeerSwitchState = recvbuf[rcv_offset++];
	p_partner_state->LocalAIDSwitchState = recvbuf[rcv_offset++];
	p_partner_state->PeerAIDSwitchState = recvbuf[rcv_offset++];
	/*接收IO数据*/
	(void)CM_Memcpy(&p_partner_state->RmtMineInputIoState[0],10,&recvbuf[rcv_offset],10);
	rcv_offset += 10u;
	(void)CM_Memcpy(&p_partner_state->RmtPeerInputIoState[0],10,&recvbuf[rcv_offset],10);
	rcv_offset += 10u;
	/*记录暗文日志*/
	(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_ANALYSIS_DATA,17u,
								sizeof(CM_UINT32),p_partner_state->LocalID,
								sizeof(CM_UINT32),s_2x2_state_Ctrl.LocalID,
								sizeof(CM_UINT32),p_partner_state->PartnerID,
								sizeof(CM_UINT32),s_2x2_state_Ctrl.PartnerID,
								sizeof(CM_UINT32),p_partner_state->SysCyc,
								sizeof(CM_UINT32),s_2x2_state_Ctrl.RxStateSysCyc,
								sizeof(CM_UINT8),p_partner_state->MicroCyc,
								sizeof(CM_UINT8),s_2x2_state_Ctrl.MicroCyc,
								sizeof(CM_UINT32),p_partner_state->TxSN,
								sizeof(CM_UINT32),s_2x2_state_Ctrl.RxSN,
								sizeof(CM_UINT32),s_2x2_state_Ctrl.LocalAIDSwitchState,
								sizeof(CM_UINT32),s_2x2_state_Ctrl.PartnerAIDSwitchState,
								sizeof(CM_UINT32),p_partner_state->LocalState,
								sizeof(CM_UINT32),s_2x2_state_Ctrl.PartnerState,
								sizeof(CM_UINT32),p_partner_state->LastLocalState,
								sizeof(CM_UINT32),s_2x2_state_Ctrl.LastPartnerState,
								sizeof(CM_UINT32),(current_time - time_stamp));
	if((msglen == (len - 4u - 6u)) &&
	   (p_partner_state->LocalID == s_2x2_state_Ctrl.PartnerID) &&
	   (p_partner_state->PartnerID == s_2x2_state_Ctrl.LocalID) &&
	   (p_partner_state->SysCyc >= s_2x2_state_Ctrl.RxStateSysCyc) &&
	   ((current_time - time_stamp) <= MSCP_2X2_STATE_OVER_TIME))
	{
		if((p_partner_state->TxSN > s_2x2_state_Ctrl.RxSN))
		{
			s_2x2_state_Ctrl.RxStateMicroCyc = p_partner_state->MicroCyc;
			s_2x2_state_Ctrl.RxStateSysCyc = p_partner_state->SysCyc;
			s_2x2_state_Ctrl.RxSN = p_partner_state->TxSN;
			s_2x2_state_Ctrl.PartnerState = p_partner_state->LocalState;
			s_2x2_state_Ctrl.LastPartnerState = p_partner_state->LastLocalState;
			/*记录对系所有接收状态*/
			s_2x2_state_Ctrl.PartnerSwitchState = p_partner_state->LocalSwitchState;
			s_2x2_state_Ctrl.PartPeerSwitchState = p_partner_state->PeerSwitchState;
			s_2x2_state_Ctrl.PartnerAIDSwitchState = p_partner_state->LocalAIDSwitchState;
			s_2x2_state_Ctrl.PartPeerAIDSwitchState = p_partner_state->PeerAIDSwitchState;
			/*记录对系IO状态*/
			(void)CM_Memcpy(s_2x2_state_Ctrl.RmtMineInputIoState,10,p_partner_state->RmtMineInputIoState,10);
			(void)CM_Memcpy(s_2x2_state_Ctrl.RmtPeerInputIoState,10,p_partner_state->RmtPeerInputIoState,10);
			SFM_LOG_MSG_2X("Analysis:OK[%d]2x2Sync-LID:0x%x-0x%x,PID:0x%x-0x%x,Scyc:%d-%d,Mcyc:%d-%d,SN:%d-%d,AID:%d-%d,State:%d-%d,LastState:%d-%d,TDv:%dms\n",s_2x2_state_Ctrl.MicroCyc,
									p_partner_state->LocalID,s_2x2_state_Ctrl.LocalID,p_partner_state->PartnerID,s_2x2_state_Ctrl.PartnerID,
									p_partner_state->SysCyc,s_2x2_state_Ctrl.RxStateSysCyc,p_partner_state->MicroCyc,s_2x2_state_Ctrl.MicroCyc,
									p_partner_state->TxSN,s_2x2_state_Ctrl.RxSN,s_2x2_state_Ctrl.LocalAIDSwitchState,s_2x2_state_Ctrl.PartnerAIDSwitchState,
									p_partner_state->LocalState,s_2x2_state_Ctrl.PartnerState,p_partner_state->LastLocalState,s_2x2_state_Ctrl.LastPartnerState,
									(current_time - time_stamp));
		}
		else
		{

		}
		rtn = CM_TRUE;
	}
	else
	{
		SFM_LOG_MSG_2X("Analysis:fail[%d]2x2Sync-LID:0x%x-0x%x,PID:0x%x-0x%x,Scyc:%d-%d,Mcyc:%d-%d,SN:%d-%d,AID:%d-%d,State:%d-%d,LastState:%d-%d,TDv:%dms\n",s_2x2_state_Ctrl.MicroCyc,
											p_partner_state->LocalID,s_2x2_state_Ctrl.LocalID,p_partner_state->PartnerID,s_2x2_state_Ctrl.PartnerID,
											p_partner_state->SysCyc,s_2x2_state_Ctrl.RxStateSysCyc,p_partner_state->MicroCyc,s_2x2_state_Ctrl.MicroCyc,
											p_partner_state->TxSN,s_2x2_state_Ctrl.RxSN,s_2x2_state_Ctrl.LocalAIDSwitchState,s_2x2_state_Ctrl.PartnerAIDSwitchState,
											p_partner_state->LocalState,s_2x2_state_Ctrl.PartnerState,p_partner_state->LastLocalState,s_2x2_state_Ctrl.LastPartnerState,
											(current_time - time_stamp));
		rtn = CM_FALSE;
	}
	return rtn;
}
/**
* @brief 2x热备状态同步
* @param pPeerCtrl 邻机热备信息
* details
* 系内交换热备信息；
* 校验2oo2双机的热备状态是否一致；
* 系内同步对系连接状态；
* 系内同步收到的状态帧信息。
*/
static ENUM_CM_RETURN s_State_2x2Sync(OUT STRU_2X2_STATE_CTRL_T *p_partner_state)
{
	/*- 变量初始化 */
	CM_INT32 rcvlen = -1;
	CM_UINT8 sendbuf[200] = {0u};
	CM_UINT8 recvbuf[200] = {0u};
	CM_UINT32 send_offset = 0u;
	ENUM_CM_RETURN retError = ENUM_CM_FALSE;
	CM_BOOL rtnCheck = CM_FALSE;
	CM_UINT64 curTick1 = 0u; /* 当前时刻 */
	CM_UINT64 curTick2 = 0u; /* 当前时刻 */
	CM_UINT64 curTick3 = 0u; /* 当前时刻 */
	CM_UINT64 sTick = 0u; /* 起始Tick */
	/*- 入参检查 */
	CM_ASSERT(NULL != p_partner_state, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_16, TSCP_DARK_ASSERT_1);

	/*- 系内交换热备状态信息 */
	retError = CM_Memset(p_partner_state, (CM_UINT8)0, sizeof(STRU_2X2_STATE_CTRL_T), sizeof(STRU_2X2_STATE_CTRL_T));
	CM_RE_ASSERT(ENUM_CM_TRUE == retError, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_16, TSCP_DARK_ASSERT_2);
	send_offset = 4u;
	/*本机ID*/
	CM_LongToChar(s_2x2_state_Ctrl.LocalID, 	&sendbuf[send_offset]);
	send_offset += 4u;
	/*对系ID*/
	CM_LongToChar(s_2x2_state_Ctrl.PartnerID, 	&sendbuf[send_offset]);
	send_offset += 4u;
	/*累加SN码*/
	s_2x2_state_Ctrl.TxSN++;
	CM_LongToChar(s_2x2_state_Ctrl.TxSN, 		&sendbuf[send_offset]);
	send_offset += 4u;
	/*系统周期号*/
	CM_LongToChar(s_2x2_state_Ctrl.SysCyc, 		&sendbuf[send_offset]);
	send_offset += 4u;
	/*微周期号*/
	sendbuf[send_offset++] = s_2x2_state_Ctrl.MicroCyc;
	/*本机当前状态*/
	CM_LongToChar(s_2x2_state_Ctrl.LocalState, 	&sendbuf[send_offset]);
	send_offset += 4u;
	/*本机上周期状态*/
	CM_LongToChar(s_2x2_state_Ctrl.LastLocalState, 	&sendbuf[send_offset]);
	send_offset += 4u;
	/*切系按钮状态*/
	sendbuf[send_offset++] = s_2x2_state_Ctrl.LocalSwitchState;
	sendbuf[send_offset++] = s_2x2_state_Ctrl.PeerSwitchState;
	/*AID切系状态*/
	sendbuf[send_offset++] = s_2x2_state_Ctrl.LocalAIDSwitchState;
	sendbuf[send_offset++] = s_2x2_state_Ctrl.PeerAIDSwitchState;
	/*IO状态组包*/
	(void)CM_Memcpy(&sendbuf[send_offset],10,s_2x2_state_Ctrl.MineInputIoState,10);
	send_offset += 10u;
	(void)CM_Memcpy(&sendbuf[send_offset],10,s_2x2_state_Ctrl.PeerInputIoState,10);
	send_offset += 10u;

	CM_LongToChar(send_offset - 4u, &sendbuf[0u]);        /*长度*/

	/*2x交互本机2取后的热备状态、按钮状态、通信状态等*/
	CFM_2x2_StateChange_Send(sendbuf,(CM_INT32)send_offset);
	/*- 串口通信通道向对系发送 */
	CFM_2x2_UartDataSend(sendbuf,(CM_UINT16)send_offset);

	sTick = CM_GetTick();
	CM_Sleep(MSCP_2X2_STATE_RCV_WITETIME);
	/*- 记录当前时间*/
	curTick1 = CM_GetTick();
	do
	{
		rcvlen = CFM_2x2_StateChange_Recv(recvbuf,200);
		if(rcvlen > 0)
		{
			/*解析2x数据*/
			rtnCheck = s_State_2x2_Analysis(p_partner_state,recvbuf,rcvlen);
			if(CM_TRUE == rtnCheck)
			{
				/*更新通信状态*/
				MSCP_UpData_2X_This_ComState(&s_2x2_state_Ctrl.MineComOKCount[0],s_2x2_state_Ctrl.SysCyc,s_2x2_state_Ctrl.MicroCyc);
				if(p_partner_state->MicroCyc == s_2x2_state_Ctrl.MicroCyc)
				{
					break;
				}
			}
			else
			{
				SFM_LOG_MSG_2X("2x2Sync:[%d]udp_2x2Sync-LID:0x%x-0x%x,PID:0x%x-0x%x,Scyc:%d-%d,Mcyc:%d-%d,SN:%d-%d\n",s_2x2_state_Ctrl.MicroCyc,
						p_partner_state->LocalID,s_2x2_state_Ctrl.LocalID,p_partner_state->PartnerID,s_2x2_state_Ctrl.PartnerID,
						p_partner_state->SysCyc,s_2x2_state_Ctrl.RxStateSysCyc,p_partner_state->MicroCyc,s_2x2_state_Ctrl.MicroCyc,
						p_partner_state->TxSN,s_2x2_state_Ctrl.RxSN);
			}
		}
		else
		{

		}
	}while(rcvlen > 0);
	curTick2 = CM_GetTick();
	do
	{
		rcvlen = CFM_2x2_UartDataRecv(recvbuf,100);
		if(rcvlen > 0)
		{
			/*解析2x数据*/
			rtnCheck = s_State_2x2_Analysis(p_partner_state,recvbuf,rcvlen);
			if(CM_TRUE == rtnCheck)
			{
				/*更新通信状态*/
				MSCP_UpData_2X_This_ComState(&s_2x2_state_Ctrl.MineUartOKCount[0],s_2x2_state_Ctrl.SysCyc,s_2x2_state_Ctrl.MicroCyc);
				if(p_partner_state->MicroCyc == s_2x2_state_Ctrl.MicroCyc)
				{
					break;
				}
			}
			else
			{
				SFM_LOG_MSG_2X("2x2Sync:[%d]uart_2x2Sync-LID:0x%x-0x%x,PID:0x%x-0x%x,Scyc:%d-%d,Mcyc:%d-%d,SN:%d-%d\n",s_2x2_state_Ctrl.MicroCyc,
						p_partner_state->LocalID,s_2x2_state_Ctrl.LocalID,p_partner_state->PartnerID,s_2x2_state_Ctrl.PartnerID,
						p_partner_state->SysCyc,s_2x2_state_Ctrl.RxStateSysCyc,p_partner_state->MicroCyc,s_2x2_state_Ctrl.MicroCyc,
						p_partner_state->TxSN,s_2x2_state_Ctrl.RxSN);
			}
		}
		else
		{

		}
	}while(rcvlen > 0);
	curTick3 = CM_GetTick();
	SFM_LOG_MSG_2X("2x2Sync:[%d]2x2Sync-recvTime:[%lldms][%lldms][%lldms]\n",s_2x2_state_Ctrl.MicroCyc,(curTick1 - sTick)/1000000,(curTick2 - sTick)/1000000,(curTick3 - sTick)/1000000);
	/*记录暗文日志*/
	(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_ANALYSIS_TIME,4u,
								sizeof(CM_UINT8),s_2x2_state_Ctrl.MicroCyc,
								sizeof(CM_UINT32),(curTick1 - sTick)/1000000u,
								sizeof(CM_UINT32),(curTick2 - sTick)/1000000u,
								sizeof(CM_UINT32),(curTick3 - sTick)/1000000u);
	return retError;
}
/**
* @brief 2x2状态机更新
* @details
* 主系在输入微周期更新
* 非主系在输出微周期更新
*/
static void s_State_Transition(void)
{
	/*- 变量初始化 */
	CM_UINT8 boardID = 0u;            /* 板卡ID */
	static CM_UINT32 dropCount = 0u;
	ENUM_CM_RETURN Flag_Sick_Down = ENUM_CM_FALSE;   /* TODO：如果自己健康度不足以升主 */
	ENUM_2x2_STATE_T TempState = ENUM_2x2_SHUTDOWN;  /*临时状态*/

	boardID = g_PFM_Cfg.BOARD_ID;
	SFM_LOG_MSG_2X("Transition:[%d]MineCom:%d-%d:%d-%d:%d-%d\r\n",s_2x2_state_Ctrl.MicroCyc,\
												s_2x2_state_Ctrl.MineComOKCount[0].SysCyc,s_2x2_state_Ctrl.MineComOKCount[0].MicroCyc,\
												s_2x2_state_Ctrl.MineComOKCount[1].SysCyc,s_2x2_state_Ctrl.MineComOKCount[1].MicroCyc,\
												s_2x2_state_Ctrl.MineComOKCount[2].SysCyc,s_2x2_state_Ctrl.MineComOKCount[2].MicroCyc);
	SFM_LOG_MSG_2X("Transition:[%d]PeerCom:%d-%d:%d-%d:%d-%d\r\n",s_2x2_state_Ctrl.MicroCyc,\
												s_2x2_state_Ctrl.PeerComOKCount[0].SysCyc,s_2x2_state_Ctrl.PeerComOKCount[0].MicroCyc,\
												s_2x2_state_Ctrl.PeerComOKCount[1].SysCyc,s_2x2_state_Ctrl.PeerComOKCount[1].MicroCyc,\
												s_2x2_state_Ctrl.PeerComOKCount[2].SysCyc,s_2x2_state_Ctrl.PeerComOKCount[2].MicroCyc);
	SFM_LOG_MSG_2X("Transition:[%d]MineUart:%d-%d:%d-%d:%d-%d\r\n",s_2x2_state_Ctrl.MicroCyc,\
												s_2x2_state_Ctrl.MineUartOKCount[0].SysCyc,s_2x2_state_Ctrl.MineUartOKCount[0].MicroCyc,\
												s_2x2_state_Ctrl.MineUartOKCount[1].SysCyc,s_2x2_state_Ctrl.MineUartOKCount[1].MicroCyc,\
												s_2x2_state_Ctrl.MineUartOKCount[2].SysCyc,s_2x2_state_Ctrl.MineUartOKCount[2].MicroCyc);
	SFM_LOG_MSG_2X("Transition:[%d]PeerUart:%d-%d:%d-%d:%d-%d\r\n",s_2x2_state_Ctrl.MicroCyc,\
												s_2x2_state_Ctrl.PeerUartOKCount[0].SysCyc,s_2x2_state_Ctrl.PeerUartOKCount[0].MicroCyc,\
												s_2x2_state_Ctrl.PeerUartOKCount[1].SysCyc,s_2x2_state_Ctrl.PeerUartOKCount[1].MicroCyc,\
												s_2x2_state_Ctrl.PeerUartOKCount[2].SysCyc,s_2x2_state_Ctrl.PeerUartOKCount[2].MicroCyc);
	/*记录暗文日志*/
	(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_COM_STATE,25u,
								sizeof(CM_UINT8),s_2x2_state_Ctrl.MicroCyc,
								sizeof(CM_UINT32),s_2x2_state_Ctrl.MineComOKCount[0].SysCyc,sizeof(CM_UINT8),s_2x2_state_Ctrl.MineComOKCount[0].MicroCyc,\
								sizeof(CM_UINT32),s_2x2_state_Ctrl.MineComOKCount[1].SysCyc,sizeof(CM_UINT8),s_2x2_state_Ctrl.MineComOKCount[1].MicroCyc,\
								sizeof(CM_UINT32),s_2x2_state_Ctrl.MineComOKCount[2].SysCyc,sizeof(CM_UINT8),s_2x2_state_Ctrl.MineComOKCount[2].MicroCyc,
								sizeof(CM_UINT32),s_2x2_state_Ctrl.PeerComOKCount[0].SysCyc,sizeof(CM_UINT8),s_2x2_state_Ctrl.PeerComOKCount[0].MicroCyc,\
								sizeof(CM_UINT32),s_2x2_state_Ctrl.PeerComOKCount[1].SysCyc,sizeof(CM_UINT8),s_2x2_state_Ctrl.PeerComOKCount[1].MicroCyc,\
								sizeof(CM_UINT32),s_2x2_state_Ctrl.PeerComOKCount[2].SysCyc,sizeof(CM_UINT8),s_2x2_state_Ctrl.PeerComOKCount[2].MicroCyc,
								sizeof(CM_UINT32),s_2x2_state_Ctrl.MineUartOKCount[0].SysCyc,sizeof(CM_UINT8),s_2x2_state_Ctrl.MineUartOKCount[0].MicroCyc,\
								sizeof(CM_UINT32),s_2x2_state_Ctrl.MineUartOKCount[1].SysCyc,sizeof(CM_UINT8),s_2x2_state_Ctrl.MineUartOKCount[1].MicroCyc,\
								sizeof(CM_UINT32),s_2x2_state_Ctrl.MineUartOKCount[2].SysCyc,sizeof(CM_UINT8),s_2x2_state_Ctrl.MineUartOKCount[2].MicroCyc,
								sizeof(CM_UINT32),s_2x2_state_Ctrl.PeerUartOKCount[0].SysCyc,sizeof(CM_UINT8),s_2x2_state_Ctrl.PeerUartOKCount[0].MicroCyc,\
								sizeof(CM_UINT32),s_2x2_state_Ctrl.PeerUartOKCount[1].SysCyc,sizeof(CM_UINT8),s_2x2_state_Ctrl.PeerUartOKCount[1].MicroCyc,\
								sizeof(CM_UINT32),s_2x2_state_Ctrl.PeerUartOKCount[2].SysCyc,sizeof(CM_UINT8),s_2x2_state_Ctrl.PeerUartOKCount[2].MicroCyc);
	/*- 是否与对系通信中断 */
	if ((CM_FALSE == MSCP_Get_2X_VagueCom_State(&s_2x2_state_Ctrl.MineComOKCount[0])) &&
		(CM_FALSE == MSCP_Get_2X_VagueCom_State(&s_2x2_state_Ctrl.PeerComOKCount[0])) &&
		(CM_FALSE == MSCP_Get_2X_VagueCom_State(&s_2x2_state_Ctrl.MineUartOKCount[0])) &&
		(CM_FALSE == MSCP_Get_2X_VagueCom_State(&s_2x2_state_Ctrl.PeerUartOKCount[0])) &&
		((s_2x2_thread_Ctrl.number_Cyc - 2) <= s_2x2_state_Ctrl.MicroCyc))
	{
		/*- 当本系为离线状态,失去链接后对系最后的状态为主系或者备系,本系离线系宕机 */
		if((ENUM_2x2_SLAVE == s_2x2_state_Ctrl.PartnerState) || (ENUM_2x2_MASTER == s_2x2_state_Ctrl.PartnerState))
		{
			if(ENUM_2x2_OFFLINE == s_2x2_state_Ctrl.LocalState)
			{
				CM_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_1);
			}
		}
		/*- 将对系状态置为宕机 */
		s_2x2_state_Ctrl.PartnerState = ENUM_2x2_SHUTDOWN;
		/*通信SN号清空-防止对系重新上电后不接收新的SN号*/
		s_2x2_state_Ctrl.RxSN = 0u;
		s_2x2_state_Ctrl.RxStateSysCyc = 0u;
	}
	else
	{
		/*- 无处理 */
	}
	/*- 热备状态 */
	switch (s_2x2_state_Ctrl.LocalState)
	{
	case ENUM_2x2_SHUTDOWN: /*-< 宕机 */
		/*- 停留在宕机状态 */
		CM_RE_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_2);
		/*- 返回 */
		break;
	case ENUM_2x2_OFFLINE: /*-< 离线 */
		/*- 自己健康度是否不足 */
		if (ENUM_CM_TRUE == Flag_Sick_Down)
		{
			/*- 自己保持离线 */
		}
		/*- 对系是否为主 */
		else if (ENUM_2x2_MASTER == s_2x2_state_Ctrl.PartnerState)
		{
			/*- 对方是主，尝试与对方同步 */
			/*- 是否与对系同步成功 */
			if ((s_2x2_state_Ctrl.SysCyc == (s_2x2_state_Ctrl.LastRxInputSysCyc + 1)) &&
				(s_2x2_state_Ctrl.SysCyc == (s_2x2_state_Ctrl.LastFollowCyc + 1)) &&
				(s_2x2_state_Ctrl.SysCyc == s_2x2_state_Ctrl.LastCheckOKCount) &&
				(0u == s_2x2_state_Ctrl.OutPutCheckFailFlag) &&
				(CM_TRUE == s_2x2_state_Ctrl.TimeSyncFlag) &&
				(0u == s_2x2_state_Ctrl.AppFollowCmpFlag))
			{
				/*- 同步成功自己转为备系 */
				s_2x2_state_Ctrl.LocalState = ENUM_2x2_SLAVE;
				SFM_LOG_MSG_2X("Transition:2x2:OFFLINE>>>>>>>SLAVE\n");
			}
			else
			{
				/*- 无处理 */
				SFM_LOG_MSG_2X("Transition:2x2:OFFLINE>SLAVE SysCyc:%d,BF:%d,AF:%d,COK:%d,OUT:%d,TS:%d,AFC:%d\n",
						s_2x2_state_Ctrl.SysCyc,s_2x2_state_Ctrl.LastRxInputSysCyc,s_2x2_state_Ctrl.LastFollowCyc,
						s_2x2_state_Ctrl.LastCheckOKCount,s_2x2_state_Ctrl.OutPutCheckFailFlag,
						s_2x2_state_Ctrl.TimeSyncFlag,
						s_2x2_state_Ctrl.AppFollowCmpFlag);
			}
			/*记录暗文日志*/
			(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_FOLLOW_STATE,7u,
										sizeof(CM_UINT32),s_2x2_state_Ctrl.SysCyc,
										sizeof(CM_UINT32),s_2x2_state_Ctrl.LastRxInputSysCyc,
										sizeof(CM_UINT32),s_2x2_state_Ctrl.LastFollowCyc,
										sizeof(CM_UINT32),s_2x2_state_Ctrl.LastCheckOKCount,
										sizeof(CM_UINT32),s_2x2_state_Ctrl.OutPutCheckFailFlag,
										sizeof(CM_UINT8),s_2x2_state_Ctrl.TimeSyncFlag,
										sizeof(CM_UINT8),s_2x2_state_Ctrl.AppFollowCmpFlag);
		}
		/*- 对系是否为预升主 */
		else if (ENUM_2x2_PRE_MASTER == s_2x2_state_Ctrl.PartnerState)
		{
			/*对方是预升主，等待对方升主*/
		}
		/*- 本系的离线计时是否达到离线保持门限 */
		else if (s_2x2_state_Ctrl.offLineCounter >= (MSCP_2x2_OFFLINE_WAIT * (s_2x2_thread_Ctrl.number_Cyc - 1u)))
		{
			/*对系离线持续足够长时间，自己才可以转为预升主*/
			/*TODO：钥匙允许自己升主*/
			/*- 本系转为预升主 */
			s_2x2_state_Ctrl.LocalState = ENUM_2x2_PRE_MASTER;
			SFM_LOG_MSG_2X("Transition:2x2:OFFLINE>>>>>>>PRE_MASTER\n");
		}
		else
		{
			/*- 保持离线 */
		}

		/*- @alias 更新离线计时器 */
		if (ENUM_2x2_OFFLINE != s_2x2_state_Ctrl.LocalState)
		{
			/*如果自己将离开离线状态，复位离线计时器*/
			s_2x2_state_Ctrl.offLineCounter = 0u;
		}
		else if (((ENUM_2x2_OFFLINE == s_2x2_state_Ctrl.PartnerState) || (ENUM_2x2_SHUTDOWN == s_2x2_state_Ctrl.PartnerState)) && (CM_TRUE == s_2x2_state_Ctrl.preMasterAllowed))
		{
			/*如果对系宕机或离线，累积离线计时*/
			if (s_2x2_state_Ctrl.offLineCounter <= (MSCP_2x2_OFFLINE_WAIT * (s_2x2_thread_Ctrl.number_Cyc - 1u)))
			{
				s_2x2_state_Ctrl.offLineCounter++;
			}
			else
			{
				/*- 无处理 */
			}
		}
		else
		{
			/*不满足条件，复位离线计时*/
			s_2x2_state_Ctrl.offLineCounter = 0u;
		}
		/*- 返回 */
		break;
	case ENUM_2x2_PRE_MASTER:/*-< 预升主 */
		/*- 自己是否健康度不足 */
		if (ENUM_CM_TRUE == Flag_Sick_Down)
		{
			/*- 本系转离线 */
			s_2x2_state_Ctrl.LocalState = ENUM_2x2_OFFLINE;
			SFM_LOG_MSG_2X("Transition:2x2:PRE_MASTER>>>>>>>OFFLINE(Unhealthy)\n");
		}
		/*TODO：如果钥匙不允许自己升主，则自己离线*/
		/*- 对系是否为主或备 */
		else if ((ENUM_2x2_MASTER == s_2x2_state_Ctrl.PartnerState) || (ENUM_2x2_SLAVE == s_2x2_state_Ctrl.PartnerState))
		{
			/*只要对方状态好，自己就不再预升主（走到这里其实对方不可能是备系，故障-安全措施）*/
			/*- 本系转离线 */
			s_2x2_state_Ctrl.LocalState = ENUM_2x2_OFFLINE;
			SFM_LOG_MSG_2X("Transition:2x2:PRE_MASTER>>>>>>>OFFLINE(Other Master)\n");
		}
		/*- 是否是本系为B系且对系预升主 */
		else if ((ENUM_2x2_PRE_MASTER == s_2x2_state_Ctrl.PartnerState) && (MSCP_MAIN_B == boardID))
		{
			/*如果对系是预升主，而自己是B系，则让给对系*/
			/*- 本系转离线 */
			s_2x2_state_Ctrl.LocalState = ENUM_2x2_OFFLINE;
			SFM_LOG_MSG_2X("Transition:2x2:PRE_MASTER>>>>>>>OFFLINE(Other A will Master)\n");
		}
		/*- 预升主计时是否达到了预升主等待时间 */
		else if (s_2x2_state_Ctrl.preMasterCounter >= (MSCP_2x2_PREMASTER_WAIT * (s_2x2_thread_Ctrl.number_Cyc - 1u)))
		{
			/*如果自己预升主等待了足够长时间，则自己升主*/
			/*- 本系升主 */
			s_2x2_state_Ctrl.LocalState = ENUM_2x2_MASTER;
			SFM_LOG_MSG_2X("Transition:2x2:PRE_MASTER>>>>>>>MASTER！！！(Will Master Success)\n");
		}
		else
		{
			/*- 保持预升主 */
		}

		/*- @alias 更新预升主计时器 */
		if (ENUM_2x2_PRE_MASTER != s_2x2_state_Ctrl.LocalState)
		{
			/*如果自己将离开预升主状态，复位离线计时器*/
			s_2x2_state_Ctrl.preMasterCounter = 0u;
		}
		else
		{
			if (s_2x2_state_Ctrl.preMasterCounter <= (MSCP_2x2_PREMASTER_WAIT * (s_2x2_thread_Ctrl.number_Cyc - 1u)))
			{
				s_2x2_state_Ctrl.preMasterCounter++;
			}
			else
			{
				/*- 无处理 */
			}
		}
		/*- 返回 */
		break;
	case ENUM_2x2_MASTER:/*-< 主系 */
		s_2x2_state_Ctrl.preMasterAllowed = CM_TRUE;		/* 主系降离线后，之后出现双离线可通过预升主升主*/
		/*如果健康度表示需要切系，则自己降离线*/
		/*- 自己是否健康度不足 */
		if (ENUM_CM_TRUE == Flag_Sick_Down)
		{
			/*- 本系降离线 */
			s_2x2_state_Ctrl.LocalState = ENUM_2x2_OFFLINE;
			s_2x2_CloseSwitchFlag();
#if 0
			s_2x2_state_Ctrl.RxBaseFollowSysCyc = 0u; /**< 收到的对系跟随数据的周期号，2oo2交换 */
			s_2x2_state_Ctrl.RxAppFollowSysCyc = 0u;  /**< 收到的对系应用跟随数据的周期号，2oo2交换 */
			s_2x2_state_Ctrl.LastFollowCyc = 0u;      /**< 上次进行平台跟随的时间，2oo2比较，*/
			s_2x2_state_Ctrl.LastAppFollowCyc = 0u;   /**< 上次进行应用跟随的时间，2oo2比较，*/
#endif
			SFM_LOG_MSG_2X("Transition:2x2:MASTER>>>>>>>OFFLINE(Unhealthy)\n");
		}
		else if(((ENUM_2x2_MASTER == s_2x2_state_Ctrl.PartnerState) || (ENUM_2x2_SLAVE == s_2x2_state_Ctrl.PartnerState)) && /*对系为备系或主系*/
				((ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.MineComOKCount[0],0u)) ||
			    (ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.PeerComOKCount[0],0u))  ||
			    (ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.MineUartOKCount[0],0u)) ||
			    (ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.PeerUartOKCount[0],0u))) && 						/*本周期任一通道正常通信*/
				((s_2x2_state_Ctrl.RxStateMicroCyc != s_2x2_state_Ctrl.MicroCyc) || (s_2x2_state_Ctrl.RxStateSysCyc != s_2x2_state_Ctrl.SysCyc)))/*接收对系周期号错误*/
		{
				/*防护因旧数据导致的双主问题*/
				s_2x2_state_Ctrl.LocalState = ENUM_2x2_OFFLINE;
				SFM_LOG_MSG_2X("Transition:2x2:MASTER>>>>>>>OFFLINE!!!(Old Data)\n");
				/* CM_RE_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_4); */
		}
		else if(ENUM_2x2_MASTER == s_2x2_state_Ctrl.PartnerState)
		{
			/*双主恢复上周期状态，如果上周期也全部为主则宕机*/
			if((ENUM_2x2_MASTER == s_2x2_state_Ctrl.LastLocalState) && (ENUM_2x2_MASTER == s_2x2_state_Ctrl.LastPartnerState))
			{
				/*- 检测到对系是主系，本系宕机*/
				s_2x2_state_Ctrl.LocalState = ENUM_2x2_SHUTDOWN;
				SFM_LOG_MSG_2X("Transition:2x2:MASTER>>>>>>>Double MASTER!!!(Shut Down)\n");
				CM_RE_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_3);
			}
			else
			{
				/*恢复上周期状态*/
				SFM_LOG_MSG_2X("Transition:2x2:Double MASTER Recovery!!!(Last State)\n");
				s_2x2_state_Ctrl.LocalState = s_2x2_state_Ctrl.LastLocalState;
				TempState = s_2x2_state_Ctrl.LastPartnerState;
				s_2x2_state_Ctrl.LastPartnerState = s_2x2_state_Ctrl.PartnerState;
				s_2x2_state_Ctrl.PartnerState = TempState;
			}

		}
		else if((ENUM_2x2_SLAVE == s_2x2_state_Ctrl.PartnerState) && (ENUM_2x2_SLAVE == s_2x2_state_Ctrl.LastPartnerState) && (ENUM_2x2_SWITCH_OPEN == s_2x2_state_Ctrl.LocalSwitchState) &&
				(ENUM_2x2_SWITCH_OPEN == s_2x2_state_Ctrl.PartnerSwitchState) && (1u == s_2x2_state_Ctrl.ctrSwitchFlag) && (0u == s_2x2_state_Ctrl.MicroCyc))
		{
			/*- 检测到对系是备系，且双系切系按钮状态为ENUM_2x2_SWITCH_OPEN，主系降为备系*/
			s_2x2_state_Ctrl.LocalState = ENUM_2x2_SLAVE;
			s_2x2_CloseSwitchFlag();
			SFM_LOG_MSG_2X("Transition:2x2:MASTER>>>>>>>SLAVE(SWITCH)\n");
		}
		else if((ENUM_2x2_SLAVE == s_2x2_state_Ctrl.PartnerState) && (1u == s_2x2_state_Ctrl.aidSwitchFlag) && (0u == s_2x2_state_Ctrl.MicroCyc))
		{
			/*- 检测到对系是备系，且允许AID切系， 主系降为备系*/
			s_2x2_state_Ctrl.LocalState = ENUM_2x2_SLAVE;
			s_2x2_CloseSwitchFlag();
			SFM_LOG_MSG_2X("Transition:2x2:MASTER>>>>>>>SLAVE(AID SWITCH)\n");
		}
		else
		{
			/*- 无处理 */
		}
		/*- 返回 */
		break;
	case ENUM_2x2_SLAVE:/*-< 备系 */
		s_2x2_state_Ctrl.preMasterAllowed = CM_FALSE;		/* 备系降离线后，禁止通过预升主升主*/
		/*- 自己是否健康度不足 */
		if (ENUM_CM_TRUE == Flag_Sick_Down)
		{
			/*- 本系降离线 */
			s_2x2_state_Ctrl.LocalState = ENUM_2x2_OFFLINE;
			SFM_LOG_MSG_2X("Transition:2x2:SLAVE>>>>>>>OFFLINE(Unhealthy)\n");
		}
		else
		{
			/*- 无处理 */
		}

		/*TODO：对系不是主而钥匙不允许自己升主，则自己离线*/
		/*- 本周期与对系的双通信通道是否全部中断 */
		if((ENUM_CM_FALSE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.MineComOKCount[0],0u)) &&
		   (ENUM_CM_FALSE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.PeerComOKCount[0],0u)) &&
		   (ENUM_CM_FALSE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.MineUartOKCount[0],0u)) &&
		   (ENUM_CM_FALSE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.PeerUartOKCount[0],0u)))
		{
			/*前两个周期是否存在中断-本周期串口是否正常-并且对系不是主系则升主*/
			if( /*与当前周期差3-5认为正常，超过阈值认为不同时断线，通信故障*/
				(MSCP_Get_2X_DisCom_Count(&s_2x2_state_Ctrl.MineComOKCount[0],0u) <= MSCP_2X2_SYNC_TIMEOUT_CYC) &&
				(MSCP_Get_2X_DisCom_Count(&s_2x2_state_Ctrl.PeerComOKCount[0],0u) <= MSCP_2X2_SYNC_TIMEOUT_CYC) &&
				(MSCP_Get_2X_DisCom_Count(&s_2x2_state_Ctrl.MineUartOKCount[0],0u) <= MSCP_2X2_SYNC_TIMEOUT_CYC) &&
				(MSCP_Get_2X_DisCom_Count(&s_2x2_state_Ctrl.PeerUartOKCount[0],0u) <= MSCP_2X2_SYNC_TIMEOUT_CYC))
			{
				/*不存在断线，判断为宕机或断电升主*/
				/*- 本系升主 */
				if(ENUM_2x2_SLAVE != s_2x2_state_Ctrl.LastLocalState && ENUM_2x2_MASTER != s_2x2_state_Ctrl.LastLocalState)
				{
					/* 升备后应用还没有成功跟随过，禁止升主，主系宕机，跟随宕机*/
					CM_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_6);
				}
				s_2x2_state_Ctrl.LocalState = ENUM_2x2_MASTER;
				s_2x2_state_Ctrl.LocalSwitchState = ENUM_2x2_SWITCH_CLOSE;
				s_2x2_state_Ctrl.PeerSwitchState = ENUM_2x2_SWITCH_CLOSE;
				s_2x2_state_Ctrl.PartnerSwitchState = ENUM_2x2_SWITCH_CLOSE;
				s_2x2_state_Ctrl.PartPeerSwitchState = ENUM_2x2_SWITCH_CLOSE;
				s_2x2_state_Ctrl.LocalAIDSwitchState = ENUM_2x2_AIDSWITCH_OVER;
				s_2x2_state_Ctrl.PeerAIDSwitchState = ENUM_2x2_AIDSWITCH_OVER;
				s_2x2_state_Ctrl.PartnerAIDSwitchState = ENUM_2x2_AIDSWITCH_OVER;
				s_2x2_state_Ctrl.PartPeerAIDSwitchState = ENUM_2x2_AIDSWITCH_OVER;
				/*- 将对系状态置为宕机 */
				s_2x2_state_Ctrl.PartnerState = ENUM_2x2_SHUTDOWN;
				/*通信SN号清空-防止对系重新上电后不接收新的SN号*/
				s_2x2_state_Ctrl.RxSN = 0u;
				s_2x2_state_Ctrl.RxStateSysCyc = 0u;
				SFM_LOG_MSG_2X("Transition:2x2:SLAVE>>>>>>>MASTER！！！(ALL interrupt)\n");
			}
			else
			{
				/*- 存在断线-宕机 */
				s_2x2_state_Ctrl.LocalState = ENUM_2x2_SHUTDOWN;
				SFM_LOG_MSG_2X("Transition:2x2:SLAVE>>>>>>>HAVE ALL interrupt(%d)(%d)(%d)(%d)\n",
						MSCP_Get_2X_DisCom_Count(&s_2x2_state_Ctrl.MineComOKCount[0],0u),
						MSCP_Get_2X_DisCom_Count(&s_2x2_state_Ctrl.PeerComOKCount[0],0u),
						MSCP_Get_2X_DisCom_Count(&s_2x2_state_Ctrl.MineUartOKCount[0],0u),
						MSCP_Get_2X_DisCom_Count(&s_2x2_state_Ctrl.PeerUartOKCount[0],0u));
				CM_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_5);
			}
		}
		else if((ENUM_2x2_MASTER != s_2x2_state_Ctrl.PartnerState) &&/*TODO 对系状态必须是最新的*/
				 (ENUM_2x2_MASTER == s_2x2_state_Ctrl.LastLocalState))
		{
			s_2x2_state_Ctrl.LocalState = ENUM_2x2_MASTER;
			s_2x2_CloseSwitchFlag();
			SFM_LOG_MSG_2X("Transition:2x2:SLAVE>>>>>>>MASTER(ROLLBACK\n");
		}
		else if(ENUM_2x2_OFFLINE == s_2x2_state_Ctrl.PartnerState)
		{
			if(ENUM_2x2_SLAVE != s_2x2_state_Ctrl.LastLocalState)
			{
				s_2x2_state_Ctrl.LocalState = ENUM_2x2_OFFLINE;
				SFM_LOG_MSG_2X("Transition:2x2:SLAVE>>>>>>>OFFLINE(Master OFFLINE SLAVE DOWN\n");
			}
			else
			{
				s_2x2_state_Ctrl.LocalState = ENUM_2x2_MASTER;
				s_2x2_CloseSwitchFlag();
				SFM_LOG_MSG_2X("Transition:2x2:SLAVE>>>>>>>MASTER(Master OFFLINE SLAVE UP\n");
			}
		}
		/*- 与主系输出不一致 或应用跟随数据不一致*/
		else if((1u == s_2x2_state_Ctrl.OutPutCheckFailFlag) || (1u == s_2x2_state_Ctrl.AppFollowCmpFlag))
		{
			s_2x2_state_Ctrl.LocalState = ENUM_2x2_OFFLINE;
			SFM_LOG_MSG_2X("Transition:2x2:SLAVE>>>>>>>OFFLINE(OutPut failed)\n");
			s_2x2_CloseSwitchFlag();
		}
		else if((ENUM_2x2_MASTER == s_2x2_state_Ctrl.PartnerState) &&
				((1u == s_2x2_state_Ctrl.aidSwitchFlag)||(1u == s_2x2_state_Ctrl.ctrSwitchFlag)) &&
				 (0u == s_2x2_state_Ctrl.MicroCyc) && (ENUM_2x2_SLAVE == s_2x2_state_Ctrl.LastLocalState))
		{
			/*是否满足至少一个以太网和任一通道*/
			if(((ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.MineComOKCount[0],0u)) &&
				(ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.PeerComOKCount[0],0u))) ||
			   ((ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.MineComOKCount[0],0u)) &&
			    (ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.MineUartOKCount[0],0u))) ||
			   ((ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.MineComOKCount[0],0u)) &&
			    (ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.PeerUartOKCount[0],0u))) ||
			   ((ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.PeerComOKCount[0],0u)) &&
			    (ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.MineUartOKCount[0],0u))) ||
			   ((ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.PeerComOKCount[0],0u)) &&
			    (ENUM_CM_TRUE == MSCP_Get_2X_Com_State(&s_2x2_state_Ctrl.PeerUartOKCount[0],0u))))
			{
				s_2x2_state_Ctrl.LocalState = ENUM_2x2_MASTER;
				SFM_LOG_MSG_2X("Transition:2x2:SLAVE>>>>>>>MASTER(SWITCH BUTTON)\n");
			}
			else
			{
				/*报警禁止切系*/
				SFM_LOG_MSG_2X("Transition:2x2:SLAVE>>>>>>>SLAVE(NOT MASTER)\n");
			}
			s_2x2_CloseSwitchFlag();
		}
		/*- 与对系是否同步超时 */
		else if ((s_2x2_state_Ctrl.SysCyc - s_2x2_state_Ctrl.LastCheckOKCount)  >= MSCP_2X2_SYNC_TIMEOUT_CYC)
		{
			/*
			* 如果失去同步，则自己离线
			* 注意，为了在双网通信中断与失去同步同时发生时能优先执行通信中断切系，这个if必须放在最后
			*/
			/*- 本系离线 */
			dropCount ++ ;
			s_2x2_state_Ctrl.LocalState = ENUM_2x2_OFFLINE;
			SFM_LOG_MSG_2X("Transition:2x2:SLAVE>>>>>>>OFFLINE(Lose Sync)\n");
		}
		else
		{
			/* 无处理 */
		}
		SFM_LOG_MSG_2X("Transition:SLAVE:live time:%d\n", s_2x2_state_Ctrl.SysCyc - s_2x2_state_Ctrl.LastCheckOKCount);
		/*- 返回 */
		break;
	default:
		/*- 返回 */
		break;
	}
}
/**
* @brief 2X状态切换独立线程
*/
static CM_THREAD_FUNC_T  SFM_2x2_StateChange_Thread(void)
{
#if QNX
    void* pmask = NULL;
    /*- 本线程锁定在 A53 core 1|2 */
    pmask = (void*)(0x01u | 0x02u);
    (void)ThreadCtl(_NTO_TCTL_RUNMASK, pmask);
#endif
    static CM_BOOL Run_First_Flag = CM_FALSE;
	CM_UINT64 curTick[6] = {0u}; /* 当前时刻 */
	CM_UINT64 sTick = 0u; /* 起始Tick */
    STRU_2OO2_NET_NO_PACK_T ctrl_2oo2_2xstate = {
    		.SN = 0u,							/*初始化SN码*/
			.DataSend = CFM_2oo2_2xStateSend,	/*注册发送函数指针*/
    		.DataRecv = CFM_2oo2_2xStateRecv};	/*注册接收函数指针*/
    STRU_2X2_STATE_CTRL_T 	peer_state; 		/**< 邻机子线程2x2状态控制 */
    STRU_2X2_STATE_CTRL_T 	partner_state; 		/**< 对系子线程2x2状态控制 */
    ENUM_2x2_STATE_T TempState = ENUM_2x2_SHUTDOWN;/*临时状态*/

	/* TODO 清空2x缓冲区数据*/
	while(1)
	{
		/*等待起始信号量*/
		CM_Sem_Wait(s_2x2_thread_Ctrl.m_Start);
		if(Run_First_Flag == CM_FALSE)
		{	/*- 首次运行清空缓冲区*/
			CFM_Net2X_State_Flush();
			Run_First_Flag = CM_TRUE;
		}
		else
		{
			/*- 无处理*/
		}
		/*微小周期执行*/
		for(s_2x2_state_Ctrl.MicroCyc = 0u;s_2x2_state_Ctrl.MicroCyc < s_2x2_thread_Ctrl.number_Cyc;s_2x2_state_Ctrl.MicroCyc++)
		{
			/*- 记录起始时间*/
			sTick = CM_GetTick();
			/*检查按钮状态*/
			s_State_Switch();
			curTick[0] = CM_GetTick();
			/*二取本机热备状态、按钮状态、通信状态等、确保双CPU数据一致*/
			s_State_2xBefore_2oo2Sync(&ctrl_2oo2_2xstate,&peer_state);
			curTick[1] = CM_GetTick();
			/*2x交互本机2取后的热备状态、按钮状态、通信状态等*/
			s_State_2x2Sync(&partner_state);
			curTick[2] = CM_GetTick();
			/*二取本机热备状态、按钮状态、通信状态等、确保双CPU数据一致*/
			s_State_2xAfter_2oo2Sync(&ctrl_2oo2_2xstate,&partner_state);
			curTick[3] = CM_GetTick();
			/*带着双cpu一致的双系数据做状态机切换*/
			if(s_2x2_state_Ctrl.MicroCyc < (s_2x2_thread_Ctrl.number_Cyc - 1u))
			{
				s_State_Transition();
			}
			else
			{
				/*预防双主*/
				if(ENUM_2x2_MASTER == s_2x2_state_Ctrl.PartnerState && ENUM_2x2_MASTER == s_2x2_state_Ctrl.LocalState)
				{
					/*双主恢复上周期状态，如果上周期也全部为主则宕机*/
					if((ENUM_2x2_MASTER == s_2x2_state_Ctrl.LastLocalState) && (ENUM_2x2_MASTER == s_2x2_state_Ctrl.LastPartnerState))
					{
						/*- 检测到对系是主系，本系宕机*/
						s_2x2_state_Ctrl.LocalState = ENUM_2x2_SHUTDOWN;
						SFM_LOG_MSG_2X("Transition:2x2:MASTER>>>>>>>Double MASTER!!!(Shut Down)\n");
						CM_RE_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_4, TSCP_DARK_ASSERT_1);
					}
					else
					{
						/*恢复上周期状态*/
						SFM_LOG_MSG_2X("Transition:2x2:Double MASTER Recovery!!!(Last State)\n");
						s_2x2_state_Ctrl.LocalState = s_2x2_state_Ctrl.LastLocalState;
						TempState = s_2x2_state_Ctrl.LastPartnerState;
						s_2x2_state_Ctrl.LastPartnerState = s_2x2_state_Ctrl.PartnerState;
						s_2x2_state_Ctrl.PartnerState = TempState;
					}
				}
			}
			curTick[4] = CM_GetTick();
			/*等待50ms周期*/
			do
			{
				/*- 记录当前时间*/
				CM_Sleep(1);
				curTick[5] = CM_GetTick();
			}while(((curTick[5] - sTick) < (MSCP_2X2_THREAD_TIME*CM_UNSIGNED_MILLION)) && (s_2x2_state_Ctrl.MicroCyc < (s_2x2_thread_Ctrl.number_Cyc-1u)) /*ms*/);
			SFM_LOG_MSG_2X("2x2_StateChange_Thread[%d],ST:%dms,2T1:%dms,XT:%dms,2T2:%dms,TT:%dms,OT:%dms,M:%d,S:%d\n",s_2x2_state_Ctrl.MicroCyc,
					(curTick[0] - sTick)/CM_UNSIGNED_MILLION,(curTick[1] - sTick)/CM_UNSIGNED_MILLION,
					(curTick[2] - sTick)/CM_UNSIGNED_MILLION,(curTick[3] - sTick)/CM_UNSIGNED_MILLION,
					(curTick[4] - sTick)/CM_UNSIGNED_MILLION,(curTick[5] - sTick)/CM_UNSIGNED_MILLION,
					s_2x2_state_Ctrl.LocalState,s_2x2_state_Ctrl.PartnerState);
			/*记录暗文日志*/
			(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_THREAD_SHOWTIME,7u,
										sizeof(CM_UINT8),s_2x2_state_Ctrl.MicroCyc,
										sizeof(CM_UINT32),(curTick[0] - sTick)/CM_UNSIGNED_MILLION,
										sizeof(CM_UINT32),(curTick[1] - sTick)/CM_UNSIGNED_MILLION,
										sizeof(CM_UINT32),(curTick[2] - sTick)/CM_UNSIGNED_MILLION,
										sizeof(CM_UINT32),(curTick[3] - sTick)/CM_UNSIGNED_MILLION,
										sizeof(CM_UINT32),(curTick[4] - sTick)/CM_UNSIGNED_MILLION,
										sizeof(CM_UINT32),(curTick[5] - sTick)/CM_UNSIGNED_MILLION);
			/*- 板卡硬件自检 3次*/
			PFM_BoardCheck_TolerateThreetimes();
		}

		/*发送2x状态结束信号量*/
		CM_Sem_Post(s_2x2_thread_Ctrl.m_Stop);
	}

	return NULL;
}
/**
* @brief 平台记录格式化字符串日志
* @param filename 文件路径
* @param func 函数名
* @param line 行号
* @param fmt 格式化字符串
*/
static void SFM_2x2_LOG_MSG(IN const CM_CHAR *filename, IN CM_INT32 line, IN const CM_CHAR* fmt, ...)
{
    /*- 变量初始化 */
    va_list argList;
    CM_CHAR msgBuf[1024];
    CM_INT32 headLen = 0;
	CM_INT32 msgLen = 0;
	if(NULL == fmt)
	{
		/* 无处理 */
	}
	else
	{
		/*- 记录文件名、函数名、行号 */
		headLen = snprintf(msgBuf, sizeof(msgBuf), "ps:%s:%d:", filename, line);
		va_start(argList, (fmt));
		/*- 记录日志内容 */
		msgLen += vsnprintf(msgBuf + headLen, sizeof(msgBuf) - (CM_SIZE_T)headLen, fmt, argList);
		va_end(argList);
#ifdef WIN32
		Bootprintf("%s", msgBuf + headLen);
#endif
	    /* printf("%s", msgBuf + headLen);*/
	    /*- 输出日志信息 */
	    CM_MQ_Write((CM_MQ_Struct_T*)&s_2x2_thread_Ctrl.LogMsgQ, (CM_UINT8*)msgBuf, (CM_UINT16)headLen + msgLen);
	}
}
/*日志转换*/
void SFM_2x2_LOG_Transition(void)
{
	ENUM_CM_RETURN rt = ENUM_CM_FALSE;
	CM_UINT8 buf[1024] = {0};
	CM_UINT16 len = 1024;
	while(1)
	{
		len = 1024;
		rt = CM_MQ_Read(&s_2x2_thread_Ctrl.LogMsgQ, buf, (CM_UINT16*)&len);
		if(ENUM_CM_TRUE == rt)
		{
		    /*- 输出日志信息 */
		    (void)CFM_BaseLog_Send((CM_UINT8*)buf, len);
		}
		else
		{
			/*无处理*/
			break;
		}
	}
}
/*发送2x起始信号*/
void SFM_2x2_Thread_PostStart(void)
{
    if (0x55u == g_PFM_Cfg.M_2x2_Enable)
    {
    	CM_Sem_Post(s_2x2_thread_Ctrl.m_Start);
    }
    else
    {
    	/* 无处理 */
    }
}
/*使能AID切系开关*/
void SFM_2x2_Enable_AIDSwitchStart(void)
{
	s_2x2_Ctrl.AIDSwitchState = ENUM_2x2_AIDSWITCH_ENABLE;
	MSCP_LOG_MSG("SFM_2x2_Enable_AIDSwitchStart:s_2x2_Ctrl.AIDSwitchState = ENUM_2x2_AIDSWITCH_ENABLE \n");
}
/*获取AID切系状态*/
ENUM_2x2_AID_SWITCH_STATE SFM_2x2_Get_AIDSwitchStart(void)
{
	return s_2x2_Ctrl.AIDSwitchState;
}
/*输出处理与发送阶段之前的等待2x逻辑结束的最后处理函数*/
void SFM_2x2_ChangeState(void)
{
	static CM_UINT8 AIDEnable_Cut = 0u;
    STRU_2X2_CTRL_T peerCtrl = { 0 };        /* 邻机热备状态 */
	/*- 等待结束信号量*/
	CM_Sem_Wait(s_2x2_thread_Ctrl.m_Stop);
	MSCP_LOG_MSG("SFM_2x2_ChangeState start\n");
	/*- 执行最后的切系逻辑*/
	s_2x2_Ctrl.MineComState  = MSCP_Get_2X_VagueCom_State(&s_2x2_state_Ctrl.MineComOKCount[0]);   /**< 本机通信状态，2oo2交换 */
	s_2x2_Ctrl.PeerComState  = MSCP_Get_2X_VagueCom_State(&s_2x2_state_Ctrl.PeerComOKCount[0]);   /**< 邻机通信状态，2oo2交换 */
	s_2x2_Ctrl.MineUartState = MSCP_Get_2X_VagueCom_State(&s_2x2_state_Ctrl.MineUartOKCount[0]);  /**< 本机串口通信状态，2oo2交换 */
	s_2x2_Ctrl.PeerUartState = MSCP_Get_2X_VagueCom_State(&s_2x2_state_Ctrl.PeerUartOKCount[0]);  /**< 邻机串口通信状态，2oo2交换 */
	/*- 切系完成*/
	if(ENUM_2x2_AIDSWITCH_OVER == s_2x2_state_Ctrl.LocalAIDSwitchState)
	{
		s_2x2_Ctrl.AIDSwitchState = ENUM_2x2_AIDSWITCH_DISABLE;
		MSCP_LOG_MSG("SFM_2x2_ChangeState:s_2x2_Ctrl.AIDSwitchState = ENUM_2x2_AIDSWITCH_DISABLE\n");
	}
	/*- 主线程认为自己是主系*/
	if (ENUM_2x2_MASTER == s_2x2_Ctrl.LocalState)
	{
		/*- 主系一直更新输出比较状态，防止切系降离线 */
		s_2x2_Ctrl.RxInputSysCyc 		= SFM_2x2_GetSysCount() - 1u;
		s_2x2_Ctrl.LastFollowCyc 		= SFM_2x2_GetSysCount() - 1u;
		s_2x2_Ctrl.LastCheckOKCount 	= SFM_2x2_GetSysCount();
		s_2x2_Ctrl.OutPutCheckFailFlag 	= 0u;
		s_2x2_Ctrl.AppFollowCmpFlag 	= 0u;
	}
	else
	{
		/*无处理*/
	}
	MSCP_LOG_MSG("timecurr 16.0.0 = %lld us\n", NOW_USED_TIME);
	/*- 记录上周期状态用于回滚*/
	s_2x2_state_Ctrl.LastLocalState = s_2x2_Ctrl.LocalState;
	s_2x2_state_Ctrl.LastPartnerState = s_2x2_Ctrl.PartnerState;
	/*- 2x线程->更新主线程热备状态*/
	s_2x2_Ctrl.LocalState = s_2x2_state_Ctrl.LocalState;
	s_2x2_Ctrl.PartnerState = s_2x2_state_Ctrl.PartnerState;
	/*- 2取双CPU同步标志与热备状态*/
	s_Ctrl_2oo2Sync(&peerCtrl);
	MSCP_LOG_MSG("timecurr 16.0.1 = %lld us\n", NOW_USED_TIME);
	/*- 主线程参数同步到2x独立线程*/
	s_2x2_state_Ctrl.LastCheckOKCount = s_2x2_Ctrl.LastCheckOKCount;
	s_2x2_state_Ctrl.OutPutCheckFailFlag = s_2x2_Ctrl.OutPutCheckFailFlag;
	s_2x2_state_Ctrl.TimeSyncFlag = s_2x2_Ctrl.TimeSyncFlag;/*更新时间同步标志*/
	s_2x2_state_Ctrl.LastRxInputSysCyc = s_2x2_Ctrl.RxInputSysCyc;
	s_2x2_state_Ctrl.LastFollowCyc = s_2x2_Ctrl.LastFollowCyc;
	s_2x2_state_Ctrl.AppFollowCmpFlag = s_2x2_Ctrl.AppFollowCmpFlag;
	/*- AID切系标志*/
	if((ENUM_2x2_AIDSWITCH_ENABLE == s_2x2_Ctrl.AIDSwitchState) && (AIDEnable_Cut <= 10u))
	{
		AIDEnable_Cut++;
	}
	else
	{
		AIDEnable_Cut = 0;
		s_2x2_Ctrl.AIDSwitchState = ENUM_2x2_AIDSWITCH_DISABLE;
	}
	s_2x2_state_Ctrl.LocalAIDSwitchState = s_2x2_Ctrl.AIDSwitchState; /**< 自己的主动切系按钮状态 */
	/*- 初始对系切系状态*/
	s_2x2_state_Ctrl.PartnerSwitchState = ENUM_2x2_SWITCH_CLOSE;
	s_2x2_state_Ctrl.PartPeerSwitchState = ENUM_2x2_SWITCH_CLOSE;
	s_2x2_state_Ctrl.PartnerAIDSwitchState = ENUM_2x2_AIDSWITCH_DISABLE;
	s_2x2_state_Ctrl.PartPeerAIDSwitchState = ENUM_2x2_AIDSWITCH_DISABLE;
	/*- 如果对系宕机，清空本系接收标志*/
	if(ENUM_2x2_SHUTDOWN == s_2x2_Ctrl.PartnerState)
	{
		s_2x2_Ctrl.RxSN = 0;
	}
	MSCP_LOG_MSG("timecurr 16.0.2 = %lld us\n", NOW_USED_TIME);
	/*- 拷贝全部IO数据*/
	(void)CM_Memcpy(s_2x2_Ctrl.MineInputIoState,10,s_2x2_state_Ctrl.MineInputIoState,10);
	(void)CM_Memcpy(s_2x2_Ctrl.PeerInputIoState,10,s_2x2_state_Ctrl.PeerInputIoState,10);
	(void)CM_Memcpy(s_2x2_Ctrl.RmtMineInputIoState,10,s_2x2_state_Ctrl.RmtMineInputIoState,10);
	(void)CM_Memcpy(s_2x2_Ctrl.RmtPeerInputIoState,10,s_2x2_state_Ctrl.RmtPeerInputIoState,10);
	/*- 清空缓冲区历史数据*/
	(void)CM_Memset(s_2x2_state_Ctrl.PeerInputIoState,0,10,10);
	(void)CM_Memset(s_2x2_state_Ctrl.RmtMineInputIoState,0,10,10);
	(void)CM_Memset(s_2x2_state_Ctrl.RmtPeerInputIoState,0,10,10);
	(void)DFM_GetIO_InPut(s_2x2_state_Ctrl.MineInputIoState,10u);/*读取IO输入数据*/
	MSCP_LOG_MSG("timecurr 16.0.0 = %lld us\n", NOW_USED_TIME);
	/*- 更新系统周期号*/
	s_2x2_state_Ctrl.SysCyc = SFM_2x2_GetSysCount(); /*系统周期号*/
	MSCP_LOG_MSG("timecurr 16.0.3 = %lld us\n", NOW_USED_TIME);
	(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_LOCAL, 1U, &s_2x2_Ctrl.LocalState);
	(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_PARTNER, 1U, &s_2x2_Ctrl.PartnerState);

	SFM_2x2_LOG_Transition();
	MSCP_LOG_MSG("timecurr 16.0.4 = %lld us\n", NOW_USED_TIME);
	MSCP_LOG_MSG("SFM_2x2_ChangeState stop\n");
}
/**
* @brief 2x2上电初始化
* @param VitalBuf 初始化关键变量数组
* @param VitalLen 初始化关键变量长度 
* @param pCycTick 上电开始时刻
* @return 周期开始时间修正量
* @details
* TODO 上电同步和上电比较
*/
void SFM_2x2_Init(IN const CM_UINT8 *VitalBuf, IN CM_UINT16 VitalLen, INOUT CM_UINT64 *pCycTick)
{
    /*- 变量初始化 */
    CM_UINT64 startTick = 0u;  /* 周期开始时间 */
    CM_UINT64 offset = 0u;     /* 最终时钟偏移量 */
    CM_UINT64 myOffset = 0u;   /* 本机时钟偏移量 */
    CM_UINT64 peerOffset = 0u; /* 邻机时钟偏移量 */
    CM_INT32 len = 0;          /* 报文长度 */
    CM_UINT8 myBuf[100] = { 0u };   /* 本机报文缓冲区 */
    CM_UINT8 peerBuf[100] = { 0u }; /* 邻机报文缓冲区 */
    ENUM_CM_RETURN checkRet = ENUM_CM_NULL;
    CM_BOOL rtnThread = CM_FALSE;
    /*- 入参检查  */
    CM_ASSERT((NULL != VitalBuf) && (NULL != pCycTick), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_7);
    /*- 是否开启2x2功能 */
    if (0x55u == g_PFM_Cfg.M_2x2_Enable)
    {

        /*- 配置参数一致性检查 */
#if (MSCP_2X2_COM_FAIL_CYC > MSCP_2X2_SYNC_TIMEOUT_CYC)
        CM_ASSERT(0u);
#endif
        /*- 变量初始化 */
        s_2x2_Ctrl.LocalState = ENUM_2x2_OFFLINE;
        s_2x2_Ctrl.PartnerState = ENUM_2x2_SHUTDOWN;
        s_2x2_Ctrl.AppFollowCmpFlag = 1u;

        /*- 更新上一周期的主备状态为这周期的主备状态(给应用用) */
        s_2x2_Ctrl.LastLocalState = s_2x2_Ctrl.LocalState;
        s_2x2_Ctrl.LastPartnerState = s_2x2_Ctrl.PartnerState;

        s_2x2_Ctrl.LocalID =(g_PFM_Cfg.BOARD_ID * 256u) + g_PFM_Cfg.CPU_ID;
        s_2x2_Ctrl.PartnerID = ((3u - (CM_UINT32)g_PFM_Cfg.BOARD_ID) * 256u) + (CM_UINT32)g_PFM_Cfg.CPU_ID;
        s_2x2_Ctrl.AIDSwitchState = 0xAA;
        s_2x2_Ctrl.TimeSyncFlag = CM_FALSE;
		/*独立线程状态结构体初始化*/
        s_2x2_state_Ctrl.LocalState = s_2x2_Ctrl.LocalState;
        s_2x2_state_Ctrl.PartnerState = s_2x2_Ctrl.PartnerState;
        /*- 更新上一周期的主备状态为这周期的主备状态(给应用用) */
        s_2x2_state_Ctrl.LastLocalState = s_2x2_Ctrl.LastLocalState;
        s_2x2_state_Ctrl.LastPartnerState = s_2x2_Ctrl.LastPartnerState;

		s_2x2_state_Ctrl.LocalAIDSwitchState = ENUM_2x2_AIDSWITCH_DISABLE;
		s_2x2_state_Ctrl.PartnerAIDSwitchState = ENUM_2x2_AIDSWITCH_DISABLE;

        s_2x2_state_Ctrl.LocalID =s_2x2_Ctrl.LocalID;
        s_2x2_state_Ctrl.PartnerID = s_2x2_Ctrl.PartnerID;
        s_2x2_state_Ctrl.TimeSyncFlag = s_2x2_Ctrl.TimeSyncFlag;
        /*独立线程参数初始化*/
        s_2x2_thread_Ctrl.number_Cyc = (g_PFM_Cfg.CYC_TIME - 60U) / MSCP_2X2_THREAD_TIME;/*根据周期计算,预留60ms*/
        (s_2x2_thread_Ctrl.number_Cyc > 1u)?(s_2x2_thread_Ctrl.number_Cyc) : (s_2x2_thread_Ctrl.number_Cyc = 1u);
        CM_Sem_Init(&s_2x2_thread_Ctrl.m_Start);
        CM_Sem_Init(&s_2x2_thread_Ctrl.m_Stop);

		s_2x2_state_Ctrl.preMasterAllowed = CM_TRUE;
        /*初始化应用跟随数据缓冲区*/
        g_TxAppFollow_len = 4;
        CM_LongToChar(0u, g_TxAppFollow);

        checkRet = CM_RB_Init(&s_2x2_TmRing, (CM_UINT32)SFM_2x2_TM_RING_SIZE);
        CM_ASSERT(ENUM_CM_TRUE == checkRet, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_1);
        /* 系间时钟同步 */
        /*- 生成系间同步报文 */
        /*
        1字节 板卡ID
        4字节 平台软件版本
        n字节 应用关键数据
        */
        s_2x2_TxSyncMsg[0] = g_PFM_Cfg.BOARD_ID;
        s_2x2_TxSyncMsg[1] = MSCP_SW_VERION[0];
        s_2x2_TxSyncMsg[2] = MSCP_SW_VERION[1];
        s_2x2_TxSyncMsg[3] = MSCP_SW_VERION[2];
        s_2x2_TxSyncMsg[4] = MSCP_SW_VERION[3];
        checkRet = CM_Memcpy((void*)(s_2x2_TxSyncMsg + 5), (CM_SIZE_T)(sizeof(s_2x2_TxSyncMsg) - 5u), VitalBuf, (CM_SIZE_T)VitalLen);
        CM_ASSERT(ENUM_CM_TRUE == checkRet, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_2);
        s_2x2_TxSyncLen = 5u + (CM_UINT32)VitalLen;

        /*- 尝试接收对系的同步报文*/
        s_2x2_RxSyncLen = CFM_2x2_SyncRecv(s_2x2_RxSyncMsg, (CM_UINT32)sizeof(s_2x2_RxSyncMsg), &s_2x2_RxSyncTick);
        /*- 是否收到了同步报文 */
        if (s_2x2_RxSyncLen > 0)
        {
            /*- 检查双系同步报文是否一致，若不一致则宕机 */
        	CM_ASSERT(s_2x2_RxSyncLen == (CM_INT32)s_2x2_TxSyncLen, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_3);
        	CM_ASSERT((s_2x2_RxSyncMsg[0] + s_2x2_TxSyncMsg[0]) == 3u, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_4);
            CM_ASSERT(0 == CM_Memcmp((void*)(s_2x2_RxSyncMsg + 1u), (void*)(s_2x2_TxSyncMsg + 1u), (CM_SIZE_T)s_2x2_TxSyncLen - 1u), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_5);
        }
        else
		{
			/*- 无处理 */
		}

        /*- 计算本机基于2oo2比较的预期周期开始时间 */
        startTick = *pCycTick;
        startTick += (CM_UINT64)(MSCP_CYC_TIME * (CM_UINT64)CM_UNSIGNED_MILLION);
        /*- 是否收到了有效的2x2同步报文且接收时间距预期周期开始时间小于2个系统周期 */
        if (((CM_UINT32)s_2x2_RxSyncLen == s_2x2_TxSyncLen) && ((startTick - s_2x2_RxSyncTick) <= (MSCP_CYC_TIME * (CM_UINT32)CM_UNSIGNED_MILLION * 2u)))
        {
        	/* 基于以上四点可做逻辑推导 */
            /*- 计算本机的时钟修正量 */
            myOffset = ((s_2x2_RxSyncTick + ((CM_UINT64)(MSCP_CYC_TIME * (CM_UINT64)CM_UNSIGNED_MILLION) * (CM_UINT64)2u)) - startTick) % (CM_UINT64)(MSCP_CYC_TIME * (CM_UINT64)CM_MILLION);
        }
        else
        {
            /*- 本机偏移量为无效值 */
            myOffset = (CM_UINT64)(MSCP_CYC_TIME * (CM_UINT64)CM_UNSIGNED_MILLION);
            MSCP_LOG_MSG("The native offset is invalid\n");
        }
        /* @alias 2oo2交换时钟修正量、取平均 */
        if (0x55u == g_PFM_Cfg.M_2oo2_Enable)
        {
            CM_64ToChar(myOffset, myBuf);
            len = SFM_2oo2_Exchange_Currency(myBuf, 8, peerBuf, (CM_UINT32)sizeof(peerBuf), ENUM_2oo2_INPUT_FULL_EX);
            CM_ASSERT(len == 8, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_6);
            peerOffset = CM_64FromChar(peerBuf);
            if ((myOffset < MSCP_CYC_TIME * CM_UNSIGNED_MILLION) && (peerOffset < (MSCP_CYC_TIME * CM_UNSIGNED_MILLION)))
            {
                offset = (myOffset + peerOffset) / 2u;
            }
            else if (myOffset < (MSCP_CYC_TIME * CM_UNSIGNED_MILLION))
            {
                offset = myOffset;
            }
            else if (peerOffset < (MSCP_CYC_TIME * CM_UNSIGNED_MILLION))
            {
                offset = peerOffset;
            }
            else
            {
                offset = (CM_UINT64)(MSCP_CYC_TIME * (CM_UINT64)CM_UNSIGNED_MILLION);
            }
        }
        else
        {
            /*- 本机计算的时钟修正量作为最终修正量 */
            offset = myOffset;
        }
        /*- offset至少为一个周期 */
        offset += (CM_UINT64)(MSCP_CYC_TIME * (CM_UINT64)CM_UNSIGNED_MILLION);
        MSCP_LOG_MSG("2x2 sync delay %lld\n", offset);

        /*- 日志队列初始化 */
        checkRet = CM_MQ_Init((CM_MQ_Struct_T*)&s_2x2_thread_Ctrl.LogMsgQ, (CM_UINT16)CFM_INNET_LOG_SIZE, (CM_UINT16)(CFM_INNET_LOG_SIZE));
        CM_ASSERT(ENUM_CM_TRUE == checkRet, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_8);
        /*-启动2x2状态切换独立线程 */
    	rtnThread = CM_Thread_Create((CM_THREAD_T*)NULL, (CM_THREAD_FUNC_T)SFM_2x2_StateChange_Thread, "2x2_Rx_state", 0, CM_TASK_PRIORITY_73, NULL);
    	CM_ASSERT(CM_TRUE == rtnThread, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_9);
    }
    else
    {
        /*- 默认本机为主 */
        s_2x2_Ctrl.LocalState = ENUM_2x2_MASTER;
        s_2x2_Ctrl.LastLocalState = s_2x2_Ctrl.LocalState;
        /*至少2个周期*/
        offset = (CM_UINT64)(MSCP_CYC_TIME * (CM_UINT64)CM_UNSIGNED_MILLION);
    } 
    /*- 更新上电开始时刻 */
    *pCycTick += offset;

}

/**
* @brief 2x2发送
* @param Data 发送报文指针
* @param DataLen 发送报文长度
* param msgType 报文类型
* @details
* @see :: s_2x2_Recv
* @see :: SFM_FrameSave
*/
void SFM_2x2_Send(IN const CM_UINT8 *Data, IN CM_UINT32 DataLen, IN ENUM_2x2_MSG_T msgType)
{

    /*- 变量初始化 */
    CM_UINT16 FrameNum = 0u;    /* 帧数 */
    CM_UINT16 FrameIndex = 0u;  /* 帧序号 */
    CM_UINT32 FrameLen = 0u;    /* 帧长度 */
    CM_UINT32 crc = 0u;         /* CRC */
    CM_UINT32 SysCyc = SFM_2x2_GetSysCount(); /* 系统周期号 */
    ENUM_CM_RETURN checkRet = ENUM_CM_NULL;
    PFM_LOG_SET_STOPTIMER(TSCP_DARK_2x2);
    /*- 入口检查 */
    CM_ASSERT(NULL != Data, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_1);

    /*- 计算帧数 */
    FrameNum = (CM_UINT16)(((CM_UINT32)DataLen <= NET_20K_SIZE) ? (1u) : ((((CM_UINT32)DataLen + NET_20K_SIZE) - 1u) / NET_20K_SIZE));
    /*
    2x2通信帧格式：
    4字节 长度（不含自身）
    4字节 源ID
    4字节 目的ID
    4字节 周期号
    4字节 序列号
    1字节 类型
    2字节 帧总数
    2字节 帧序号
    n字节 数据
    4字节 CRC（含长度）
    */
    /*- 填充报文头 */
    CM_LongToChar(NET_20K_SIZE + 25u, &s_2x2_Cache[0u]);        /*长度(暂时填写满帧)*/
    CM_LongToChar(s_2x2_Ctrl.LocalID, &s_2x2_Cache[4u]);   /*源ID*/
    CM_LongToChar(s_2x2_Ctrl.PartnerID, &s_2x2_Cache[8u]); /*目的ID*/
    CM_LongToChar(SysCyc, &s_2x2_Cache[12u]);              /*周期号*/
    s_2x2_Ctrl.TxSN++;
    CM_LongToChar(s_2x2_Ctrl.TxSN, &s_2x2_Cache[16u]);     /*序列号*/    
    s_2x2_Cache[20] = (CM_UINT8)msgType;                  /*类型*/
    CM_ShortToChar(FrameNum, &s_2x2_Cache[21u]);           /*帧总数*/
    /* s_2x2_Cache + 23 */                                /*帧序号(后面填写)*/

    /*- @alias 循环发送完整帧 */
    for (FrameIndex = 1u; FrameIndex < FrameNum; FrameIndex++)
    {
        
        CM_ShortToChar(FrameIndex, &s_2x2_Cache[23u]);         /*帧序号*/
        checkRet = CM_Memcpy((void*)(&s_2x2_Cache[25u]), (CM_SIZE_T)NET_20K_SIZE, (const void*)(Data + ((FrameIndex - 1u)*NET_20K_SIZE)), (CM_SIZE_T)NET_20K_SIZE); /* parasoft-suppress MISRA2004-17_1 MISRA2004-17_4 "指针运算提高代码执行效率" */
        CM_RE_ASSERT(checkRet == ENUM_CM_TRUE, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_2);
        crc = CM_Crc32(s_2x2_Cache, NET_20K_SIZE + 25u);
        CM_LongToChar(crc, &s_2x2_Cache[25u + NET_20K_SIZE]); /*CRC*/

        (void)CFM_2x2_DataSend(s_2x2_Cache, (CM_INT32)(29u + NET_20K_SIZE));  /*交给通信层发送*/
    }

    /*- 发送尾帧*/
    CM_ShortToChar(FrameIndex, &s_2x2_Cache[23u]);         /*帧序号*/
    FrameLen = (CM_UINT32)DataLen - ((FrameIndex - 1u)*NET_20K_SIZE);
    checkRet = CM_Memcpy((void*)(&s_2x2_Cache[25u]), (CM_SIZE_T)NET_20K_SIZE, (const void*)(Data + ((FrameIndex - 1u)*NET_20K_SIZE)), (CM_SIZE_T)FrameLen); /* parasoft-suppress MISRA2004-17_1 MISRA2004-17_4 "指针运算提高代码执行效率" */
    CM_RE_ASSERT(checkRet == ENUM_CM_TRUE, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_3);
    CM_LongToChar(25u + FrameLen, s_2x2_Cache);              /*长度*/
    crc = CM_Crc32(s_2x2_Cache, 25u + FrameLen);
    CM_LongToChar(crc, &s_2x2_Cache[25u + FrameLen]);      /*CRC*/
    (void)CFM_2x2_DataSend(s_2x2_Cache,(CM_INT32)CM_UNSIGNED_INT_EXP(29u + FrameLen));         /*交给通信层发送*/
    PFM_LOG_SET_STOPTIMER(TSCP_DARK_NULL);
}

/**
* @brief 2x2周期同步
* @param cycTick 周期开始时刻
*/
void SFM_2x2_Sync(IN CM_UINT64 cycTick, OUT CM_INT64 *pOffset)
{
	/*本周期同步标志*/
	static ENUM_CM_RETURN g_syncFlag = ENUM_CM_FALSE;
	static CM_INT32 s_count = 0;
	static CM_INT64 s_sum = 0;
	static CM_INT32 s_nsub = 0;
	static CM_INT32 s_nadd = 0;
	if(NULL == pOffset)
	{
		MSCP_LOG_MSG("ERROR: NULL !!! \n");
		CM_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_1);
		/*- 无需操作 */
	}
	else
	{
		 /*- 变量初始化 */
	    CM_INT64 myDelay = 0;  /* 本机延迟 */
	    CM_INT64 myOffset = 0; /* 本机偏移 */
	    CM_INT64 peerOffset = 0;/* 邻机偏移 */
	    CM_INT64 aveOffset = 0; /* 平均偏移量 */
	    CM_INT64 offset = 0;   /* 修正量 */
	    CM_INT64 cyctime_ns = 0;   /* 周期时间ns值 */
	    CM_INT64 val = 0;     /* 临时变量 */
	    CM_UINT8 myBuf[32] = {0u};   /* 2oo2缓冲区 */
	    CM_UINT8 peerBuf[32] = {0u}; /* 2oo2缓冲区 */
	    ENUM_CM_RETURN rt = ENUM_CM_FALSE;  /* 函数返回值 */
		ENUM_2x2_STATE_T state_2x2 = ENUM_2x2_SHUTDOWN; /* 本系热备状态 */
	    *pOffset = 0;
	    (void)CFM_2x2_SyncSend(s_2x2_TxSyncMsg, (CM_INT32)s_2x2_TxSyncLen);
	    s_2x2_RxSyncLen = CFM_2x2_SyncRecv(s_2x2_RxSyncMsg, (CM_UINT32)sizeof(s_2x2_RxSyncMsg), &s_2x2_RxSyncTick);
	    /*TODO 统计、调整*/
	    /*- 是否收到对系的周期同步报文 */
	    if (s_2x2_RxSyncLen > 0)
	    {
	        /*- 获取本系状态 */
	    	state_2x2 = SFM_2x2_GetLocal2x2State();
	    	MSCP_LOG_MSG("Obtain department status Obtain department status = %d\n",state_2x2);
	        /*- 本系是否非主 */
	    	if(ENUM_2x2_MASTER != state_2x2)
	    	{
	            /*- 判断本系的关键数据是否与对系一致，若不一致，则本系宕机 */
	    		CM_RE_ASSERT(0 == CM_Memcmp((void*)(s_2x2_RxSyncMsg + 1), (void*)(s_2x2_TxSyncMsg + 1), (CM_SIZE_T)s_2x2_TxSyncLen - 1u), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_2);
	    	}
	    	else
	    	{
	            /*- 无需操作 */
	    	}
	    }
	    else
	    {
	        /*- 无需操作 */
	    }
	    myOffset = CM_INT64_MAX;
	    rt = CFM_2x2_TimeGet(&myDelay, &myOffset);
	    /*- 是不是修正完的下一周期,如果是则offset无效  */
	    if(ENUM_CM_TRUE == g_syncFlag)
	    {
	    	myOffset = CM_INT64_MAX;
	    	g_syncFlag = ENUM_CM_FALSE;
	    }
	    else
	    {
	    	/*- 无需操作 */
	    }

	    MSCP_LOG_MSG("myOffset = %lld\n",myOffset);
	    CFM_2x2_TimeReq();
	    MSCP_LOG_MSG("CFM_2x2_TimeReq\n");
	    if (g_PFM_Cfg.M_2oo2_Enable == 0x55u)
	    {
	        CM_64ToChar(myOffset, myBuf);
	        (void)SFM_2oo2_Exchange_Currency(myBuf, 8, peerBuf, 8u, (CM_UINT32)ENUM_2oo2_SYNC);
	        peerOffset = CM_64FromChar(peerBuf);
	        if ((myOffset < CM_INT64_MAX) && (peerOffset < CM_INT64_MAX) && (myOffset > CM_INT64_MIN) && (peerOffset > CM_INT64_MIN))
	        {
	            myOffset = (myOffset + peerOffset) / 2;
	            MSCP_LOG_MSG("myOffset = %d,The calibration result is the average value of 2OO2 dual machines\n", myOffset);
	            rt = ENUM_CM_TRUE;
	        }
	        else if ((myOffset < CM_INT64_MAX) && (myOffset > CM_INT64_MIN))
	        {
	        	MSCP_LOG_MSG("The calibration result is the local calibration result\n");
	            rt = ENUM_CM_TRUE;
	        }
	        else if ((peerOffset < CM_INT64_MAX) && (peerOffset > CM_INT64_MIN))
	        {
	        	MSCP_LOG_MSG("The calibration result is the calibration result of the neighboring machine\n");
	            myOffset = peerOffset;
	            rt = ENUM_CM_TRUE;
	        }
	        else
	        {
	            rt = ENUM_CM_FALSE;
	            MSCP_LOG_MSG("Failed to calibrate this period\n");
	        }
	    }
	    else
	    {
	    	/*- 无需操作 */
	    }

	    if (ENUM_CM_TRUE == rt)
	    {
		    if((myOffset >= (20 * CM_MILLION)) || (myOffset <= -(20 * CM_MILLION)))
		    {
		    	MSCP_LOG_MSG("WARING[%d][%lldms]:2X offset deviation is too large\n",SFM_2x2_GetSysCount(),myOffset/CM_MILLION);
		    	s_2x2_Ctrl.TimeSyncFlag = CM_FALSE;
		    }
		    else
		    {
		    	/*- 无需操作 */
		    	MSCP_LOG_MSG("WARING[%d][%lldms]:2X offset sync success\n",SFM_2x2_GetSysCount(),myOffset/CM_MILLION);
		    	s_2x2_Ctrl.TimeSyncFlag = CM_TRUE;
		    }
	    	if(ENUM_2x2_OFFLINE == s_2x2_Ctrl.LocalState)
	    	{
				aveOffset = myOffset;
				g_syncFlag = ENUM_CM_TRUE;
	    	}
	    	else
	    	{
				(void)CM_RB_Get(&s_2x2_TmRing, (CM_UINT16)SFM_2x2_TM_RING_SIZE, &val);
				s_sum -= val;
				(void)CM_RB_Write(&s_2x2_TmRing, myOffset);
				s_sum += myOffset;
				s_count++;
				MSCP_LOG_MSG("Whether effective calibration results have been achieved %lld(ns)\n",s_sum);
				if (s_count >= SFM_2x2_TM_RING_SIZE)
				{
					aveOffset = (s_sum) / (CM_INT64)SFM_2x2_TM_RING_SIZE;
					g_syncFlag = ENUM_CM_TRUE;
				}
				else
				{

				}
	    	}
			if (ENUM_CM_TRUE == g_syncFlag)
			{
				if (aveOffset >= (SFM_2x2_TM_FIX_VAL * CM_MILLION))
				{
					offset = -aveOffset;
					MSCP_LOG_MSG("offset = %lld\n",offset);
					s_nsub++;
					s_count = 0;
				}
				else if (aveOffset <= (-SFM_2x2_TM_FIX_VAL * CM_MILLION))
				{
					offset = -aveOffset;
					MSCP_LOG_MSG("offset = %lld\n",offset);
					s_nadd++;
					s_count = 0;
				}
				else
				{
					/*- 无需操作 */
				}
			}
			else
			{
				/*- 无需操作 */
			}
	    }
	    else
	    {
	    	/*- 无需操作 */
	    }
	    /*- 是否对系为主系 */
	    if (ENUM_2x2_MASTER == s_2x2_Ctrl.PartnerState)
	    {
	    	cyctime_ns = (CM_INT64)(g_PFM_Cfg.CYC_TIME) * CM_MILLION;
	        /*- 是否需要调大时钟超过一周期 */
	        if (offset >= cyctime_ns)
	        {
	            /*- 本次只做周期基准时间调整，不调整周期定时器 （将偏移量四舍五入到整周期）*/
	            *pOffset = ((CM_INT64)(offset + cyctime_ns / 2) / cyctime_ns) * cyctime_ns;
	            MSCP_LOG_MSG("Increase the clock by more than one cycle *pOffset = %lld\n",*pOffset);
	        }
	        /*- 是否需要调小时钟超过一周期 */
	        else if (offset <= -cyctime_ns)
	        {
	            /*- 本次只做周期基准时间调整，不调整周期定时器 （将偏移量四舍五入到整周期） */
	            *pOffset = ((CM_INT64)(offset - cyctime_ns / 2) / cyctime_ns) * cyctime_ns;
	            MSCP_LOG_MSG("Set the clock more than one cycle*pOffset = %lld\n",*pOffset);
	        }
	        /*- 是否需要调大时钟不超过一周期 */
	        else if (offset >= (CM_INT64)SFM_2x2_TM_FIX_VAL * CM_MILLION)
	        {
	            /*- 本周期定时器延长10ms */
	            *pOffset = SFM_2x2_TM_FIX_VAL * CM_MILLION;
	            MSCP_LOG_MSG("The interval timer is extended by 10ms\n");
	        }
	        /*- 是否需要调小时钟不超过一周期 */
	        else if (offset <= -(CM_INT64)SFM_2x2_TM_FIX_VAL * CM_MILLION)
	        {
	            /*- 本周期定时器缩短10ms */
	            *pOffset = -SFM_2x2_TM_FIX_VAL * CM_MILLION;
	            MSCP_LOG_MSG("The interval timer is shortened by 10ms\n");
	        }
	        else
	        {
	            /*- 不需要调整时钟 */
	            *pOffset = 0;
	        }
	    }
	    else
	    {
	        /*- 不需要调整时钟 */
	        *pOffset = 0;
	    }
	    /*- 记录同步结果 */
	    MSCP_LOG_MSG("2x2 sync:%lld,%lld,%lld(us)\n", myOffset / 1000, peerOffset / 1000, *pOffset/1000);
	    MSCP_LOG_MSG("2x2 offset_sum:%lld(us),%d,%d\n", s_sum / 1000, s_nadd, s_nsub);
	    /*记录暗文日志*/
		(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_SYNC_TIME,8u,
									sizeof(CM_UINT8),s_2x2_Ctrl.TimeSyncFlag,
									sizeof(CM_UINT32),SFM_2x2_GetSysCount(),
									sizeof(CM_UINT32),myOffset / 1000,
									sizeof(CM_UINT32),peerOffset / 1000,
									sizeof(CM_UINT32),*pOffset / 1000,
									sizeof(CM_UINT32),s_sum / 1000,
									sizeof(CM_UINT32),s_nadd,
									sizeof(CM_UINT32),s_nsub);
	}
}

/**
* @brief 2x2接收
* @see :: SFM_2x2_Send
* @see :: s_2x2_SendState
*/
static void s_2x2_Recv(void)
{
    /*- 变量初始化 */
    static STRU_FrameCtrl_T s_2x2_FrameCtrl; /**< 分帧接收控制 */
    CM_INT32 rxLen = 0;       /* 网络接收长度 */
    CM_UINT32 msgLen = 0u;    /* 报文长度 */
    CM_UINT32 SrcID = 0u;     /* 源ID */
    CM_UINT32 DstID = 0u;     /* 目的ID */
    CM_UINT32 msgCyc = 0u;    /* 报文周期号 */
    CM_UINT32 msgSN = 0u;     /* 报文序列号 */
    CM_UINT16 FrameNum = 0u;  /* 帧数目 */
    CM_UINT16 FrameIndex = 0u;/* 帧序号 */
    CM_UINT32 msgCrc = 0u;    /* 报文CRC */
    CM_UINT32 calcCrc = 0u;   /* 本地计算CRC */
    CM_UINT8 *pData = NULL;   /* 指向帧数据的指针 */
    CM_INT32 DataLen = 0;     /* 帧数据长度 */
    ENUM_2x2_MSG_T type = ENUM_2x2_MSG_ERROR; /* 报文类型 */
    ENUM_CM_RETURN ret = ENUM_CM_FALSE;          /* 临时变量 */
    PFM_LOG_SET_STOPTIMER(TSCP_DARK_2x2);
    /*- 以太网循环接收2x2数据 */
    if(CM_TRUE == s_2x2_Ctrl.TimeSyncFlag)
    {
		do
		{
			/*- 从通信层接收2x2报文 */
			rxLen = CFM_2x2_DataRecv(s_2x2_Cache, (CM_UINT32)sizeof(s_2x2_Cache));
			/*- 收到的报文长度是否大于0 */
			if ((29 <= rxLen))
			{
				/*- 解析2x2报文头 */
				/*
				2x2通信帧格式：
				4字节 长度（不含自身）
				4字节 源ID
				4字节 目的ID
				4字节 周期号
				4字节 序列号
				1字节 类型
				2字节 帧总数
				2字节 帧序号
				n字节 数据
				4字节 CRC
				*/
				msgLen = CM_LongFromChar(s_2x2_Cache);
				CM_RE_ASSERT((msgLen + 4u) == (CM_UINT32)rxLen, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_1);
				SrcID = CM_LongFromChar(s_2x2_Cache + 4);
				DstID = CM_LongFromChar(s_2x2_Cache + 8);
				msgCyc = CM_LongFromChar(s_2x2_Cache + 12);
				msgSN = CM_LongFromChar(s_2x2_Cache + 16);
				type = (ENUM_2x2_MSG_T)s_2x2_Cache[20];
				FrameNum = CM_ShortFromChar(s_2x2_Cache + 21);
				FrameIndex = CM_ShortFromChar(s_2x2_Cache + 23);
				msgCrc = CM_LongFromChar(s_2x2_Cache + msgLen);
				calcCrc = CM_Crc32(s_2x2_Cache, msgLen);
				/*- 校验报文头是否合法 */
				if ((SrcID == s_2x2_Ctrl.PartnerID)
					&& (DstID == s_2x2_Ctrl.LocalID)
					/*&& msgCyc*/
					&& (msgSN >= s_2x2_Ctrl.RxSN)
					&& (msgCrc == calcCrc))
				{
					/*- 更新通信状态 */
					s_2x2_Ctrl.RxSN = msgSN;
					pData = s_2x2_Cache + 25;
					DataLen = (CM_INT32)CM_UNSIGNED_INT_EXP(msgLen - 25u);
					/*- 报文类型 */
					switch (type)
					{
					case ENUM_2x2_MSG_BASE_FOLLOW:/*-< 平台跟随数据*/
						/*- @alias 分帧接收新跟随报文 */
						if (msgCyc > s_2x2_Ctrl.RxBaseFollowSysCyc)
						{
							/*- 分帧接收跟随报文 */
							CM_RE_ASSERT(FrameNum <= (SFM_FOLLOW_BUFF_SIZE / NET_20K_SIZE), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_2);
							CM_RE_ASSERT(FrameIndex <= FrameNum, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_3);
							ret = SFM_2X_FrameSave(&s_2x2_FrameCtrl, (CM_UINT8)ENUM_2x2_MSG_BASE_FOLLOW, FrameNum, FrameIndex, pData, DataLen, g_RxBaseFollow, &g_RxBaseFollow_len, (CM_UINT32)sizeof(g_RxBaseFollow));
							/*- 是否收齐了跟随报文 */
							if (ENUM_CM_TRUE == ret)
							{
								/*- 更新跟随报文状态 */
								CM_RE_ASSERT(16 <= g_RxBaseFollow_len, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_4);
								s_2x2_Ctrl.RxBaseFollowSysCyc = msgCyc;
								MSCP_LOG_MSG("2x2 RxBaseFollowCyc = %d,rcvlen = %d,Time:%d us\r\n", msgCyc,g_RxBaseFollow_len,NOW_USED_TIME);
							}
							else
							{
								MSCP_LOG_MSG("2x2 msgCyc = %d, SysCyc = %d,Time:%d us\r\n", msgCyc, s_2x2_Ctrl.RxBaseFollowSysCyc,NOW_USED_TIME);
							}
						}
						else
						{
							MSCP_LOG_MSG("2x2 msgCyc = %d > SysCyc = %d,Time:%d us\r\n", msgCyc, s_2x2_Ctrl.RxBaseFollowSysCyc,NOW_USED_TIME);
						}
						/*记录暗文日志*/
						(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_RCV_BASE_STATE,5u,
													sizeof(CM_UINT8),(msgCyc > s_2x2_Ctrl.RxBaseFollowSysCyc),
													sizeof(CM_UINT32),msgCyc,
													sizeof(CM_UINT32),s_2x2_Ctrl.RxBaseFollowSysCyc,
													sizeof(CM_UINT32),g_RxBaseFollow_len,
													sizeof(CM_UINT32),NOW_USED_TIME);
						/*- 返回 */
						break;
					case ENUM_2x2_MSG_APP_FOLLOW:/*-< 应用跟随报文 */
						/*- @alias 分帧接收新跟随报文 */
						if (msgCyc > s_2x2_Ctrl.RxAppFollowSysCyc)
						{
							/*- 分帧接收跟随报文 */
							CM_RE_ASSERT(FrameNum <= (SFM_FOLLOW_BUFF_SIZE / NET_20K_SIZE), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_5);
							CM_RE_ASSERT(FrameIndex <= FrameNum, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_6);
							ret = SFM_2X_FrameSave(&s_2x2_FrameCtrl, (CM_UINT8)ENUM_2x2_MSG_APP_FOLLOW, FrameNum, FrameIndex, pData, DataLen, g_RxAppFollow, &g_RxAppFollow_len, (CM_UINT32)sizeof(g_RxAppFollow));
							/*- 是否收齐了跟随报文 */
							if (ENUM_CM_TRUE == ret)
							{
								/*- 更新跟随报文状态 */
								CM_RE_ASSERT(4 <= g_RxAppFollow_len, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_7);
								s_2x2_Ctrl.RxAppFollowSysCyc = msgCyc;
								MSCP_LOG_MSG("2x2 RxAppFollowCyc = %d,rcvlen = %d,Time:%d us\r\n", msgCyc,g_RxAppFollow_len,NOW_USED_TIME);
							}
							else
							{
								/*- 无处理 */
							}
						}
						else
						{
							/*- 无处理 */
						}
						/*记录暗文日志*/
						(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_RCV_APP_STATE,5u,
													sizeof(CM_UINT8),(msgCyc > s_2x2_Ctrl.RxAppFollowSysCyc),
													sizeof(CM_UINT32),msgCyc,
													sizeof(CM_UINT32),s_2x2_Ctrl.RxAppFollowSysCyc,
													sizeof(CM_UINT32),g_RxAppFollow_len,
													sizeof(CM_UINT32),NOW_USED_TIME);
						break;
					case ENUM_2x2_MSG_APP_FOLLOW_CRC:/*-< 应用跟随报文 只比较CRC */
						/*- @alias 分帧接收新跟随报文 */
						if (msgCyc > s_2x2_Ctrl.RxAppFollowSysCyc)
						{
							/*- 分帧接收跟随报文 */
							CM_RE_ASSERT(FrameNum <= (SFM_FOLLOW_BUFF_SIZE / NET_20K_SIZE), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_17);
							CM_RE_ASSERT(FrameIndex <= FrameNum, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_19);
							ret = SFM_2X_FrameSave(&s_2x2_FrameCtrl, (CM_UINT8)ENUM_2x2_MSG_APP_FOLLOW_CRC, FrameNum, FrameIndex, pData, DataLen, g_RxAppFollowCrc, &g_RxAppFollowCrc_len, (CM_UINT32)sizeof(g_RxAppFollowCrc));
							/*- 是否收齐了跟随报文 */
							if (ENUM_CM_TRUE == ret)
							{
								/*- 更新跟随报文状态 */
								CM_RE_ASSERT(12 == g_RxAppFollowCrc_len, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_18);
								s_2x2_Ctrl.RxAppFollowSysCyc = msgCyc;
								MSCP_LOG_MSG("2x2 RxAppFollowCrcCyc = %d,rcvlen = %d,Time:%d us\r\n", msgCyc,g_RxAppFollowCrc_len,NOW_USED_TIME);
							}
							else
							{
								/*- 无处理 */
							}
						}
						else
						{
							/*- 无处理 */
						}
						/*记录暗文日志*/
						(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_RCV_APP_STATE_CRC,5u,
													sizeof(CM_UINT8),(msgCyc > s_2x2_Ctrl.RxAppFollowSysCyc),
													sizeof(CM_UINT32),msgCyc,
													sizeof(CM_UINT32),s_2x2_Ctrl.RxAppFollowSysCyc,
													sizeof(CM_UINT32),g_RxAppFollowCrc_len,
													sizeof(CM_UINT32),NOW_USED_TIME);
						break;
					case ENUM_2x2_MSG_OUTCHECK:/*-< 输出校验报文*/
						/*- @alias 接收新输出校验报文 */
						if (msgCyc > s_2x2_Ctrl.RxCheckSysCyc)
						{
							/*- 保存输出校验报文 */
							MSCP_LOG_MSG("2x2 Out RxCheckCyc = %d,Time:%d us\n", s_2x2_Ctrl.RxCheckSysCyc,NOW_USED_TIME);
							s_2x2_Ctrl.RxCheckSysCyc = msgCyc;
							s_2x2_Ctrl.RxCheckLen = DataLen;
							ret = CM_Memset(s_2x2_Ctrl.RxCheckFrame, (CM_UINT8)0, sizeof(s_2x2_Ctrl.RxCheckFrame), sizeof(s_2x2_Ctrl.RxCheckFrame));
							CM_RE_ASSERT(ENUM_CM_TRUE == ret, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_8);
							ret = CM_Memcpy((void*)s_2x2_Ctrl.RxCheckFrame, sizeof(s_2x2_Ctrl.RxCheckFrame), (void*)pData, (CM_SIZE_T)DataLen);
							CM_RE_ASSERT(ENUM_CM_TRUE == ret, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_9);
						}
						else
						{
							/*- 无处理 */
							MSCP_LOG_MSG("2x2 Out msgCyc = %d,RxCheckCyc = %d,Time:%d us\n", msgCyc,s_2x2_Ctrl.RxCheckSysCyc,NOW_USED_TIME);
						}
						/*记录暗文日志*/
						(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_RCV_CHECK_STATE,5u,
													sizeof(CM_UINT8),(msgCyc > s_2x2_Ctrl.RxCheckSysCyc),
													sizeof(CM_UINT32),msgCyc,
													sizeof(CM_UINT32),s_2x2_Ctrl.RxCheckSysCyc,
													sizeof(CM_UINT32),DataLen,
													sizeof(CM_UINT32),NOW_USED_TIME);
						/*- 返回 */
						break;
					case ENUM_2x2_MSG_ERROR:/*-< 保留字*/
						/*- 宕机 */
						CM_RE_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_10);
						/*- 返回 */
						break;
					default:
						/*- 是否是对系本机输入数据同步报文 */
						if ((type >= 1) && (type <= g_2x2RcvMaxNum[0]))
						{
							/*- 是否收到新同步报文 */
							if (msgCyc >= s_2x2_Ctrl.RxInputSysCyc)
							{
								/*- 分帧接收数据同步报文 */
								CM_RE_ASSERT(FrameNum <= (SFM_OUTNETSAFE_BUFF_SIZE / NET_20K_SIZE), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_11);
								CM_RE_ASSERT(FrameIndex <= FrameNum, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_12);
								ret = SFM_2X_FrameSave(&s_2x2_FrameCtrl, (CM_UINT8)type, FrameNum, FrameIndex, pData, DataLen,
									g_2x2oo2_rx[g_2x2oo2_base][type].p_rmt_mine_buf,
									&g_2x2oo2_rx[g_2x2oo2_base][type].rmt_mine_len,
									(CM_UINT32)g_2x2oo2_rx[g_2x2oo2_base][type].buf_size);
								/*记录本机收到对系数据长度*/
								s_2x2_Ctrl.InPutDoublePassLen[type][0] = g_2x2oo2_rx[g_2x2oo2_base][type].rmt_mine_len;	
								/*- 是否收齐了全部数据同步报文 */
								if ((ENUM_CM_TRUE == ret) && (type == g_2x2RcvMaxNum[0]))
								{
									/*- 更新对系输入状态 */
									s_2x2_Ctrl.InputMineSysCyc = msgCyc;
									MSCP_LOG_MSG("ret = %d, type = %d, 2x2RcvMaxNum = %d\r\n", ret, type, g_2x2RcvMaxNum[0]);
									if((msgCyc == s_2x2_Ctrl.InputMineSysCyc) && (msgCyc == s_2x2_Ctrl.InputPeerSysCyc))
									{
										/*- 更新对系本机输入数据同步报文周期号 */
										s_2x2_Ctrl.RxInputSysCyc = msgCyc;
										MSCP_LOG_MSG("s_2x2_Ctrl.RxInputSysCyc = %d\r\n", s_2x2_Ctrl.RxInputSysCyc);
									}
									else
									{
										/*- 无处理 */
									}
								}
								else
								{
									/*- 无处理 */
								}
							}
							else
							{
								/*- 无处理 */
								MSCP_LOG_MSG("msgCyc = %d, s_2x2_Ctrl.RxInputSysCyc = %d\r\n", msgCyc, s_2x2_Ctrl.RxInputSysCyc);
							}
						}
						/*- 是否是对系邻机输入数据同步报文 */
						else if((type >= (g_2x2oo2_data_num+1) ) && (type <= g_2x2RcvMaxNum[1]))
						{
							/*- 是否收到新同步报文 */
							if (msgCyc >= s_2x2_Ctrl.RxInputSysCyc)
							{
								/*- 分帧接收数据同步报文 */
								CM_RE_ASSERT(FrameNum <= (SFM_OUTNETSAFE_BUFF_SIZE / NET_20K_SIZE), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_15);
								CM_RE_ASSERT(FrameIndex <= FrameNum, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_16);
								ret = SFM_2X_FrameSave(&s_2x2_FrameCtrl, (CM_UINT8)type, FrameNum, FrameIndex, pData, DataLen,
									g_2x2oo2_rx[g_2x2oo2_base][(CM_INT32)type-g_2x2oo2_data_num].p_rmt_peer_buf,
									&g_2x2oo2_rx[g_2x2oo2_base][(CM_INT32)type-g_2x2oo2_data_num].rmt_peer_len,
									(CM_UINT32)g_2x2oo2_rx[g_2x2oo2_base][(CM_INT32)type-g_2x2oo2_data_num].buf_size);
								/*记录对系邻机数据长度*/
								s_2x2_Ctrl.InPutDoublePassLen[(CM_INT32)type-g_2x2oo2_data_num][1] = g_2x2oo2_rx[g_2x2oo2_base][(CM_INT32)type-g_2x2oo2_data_num].rmt_peer_len;	
								/*- 是否收齐了全部数据同步报文 */
								if ((ENUM_CM_TRUE == ret) && ((CM_UINT8)type == g_2x2RcvMaxNum[1]))
								{
									/*- 更新对系输入状态 */
									s_2x2_Ctrl.InputPeerSysCyc = msgCyc;
									MSCP_LOG_MSG("p_rmt_peer_buf ret = %d, type = %d, 2x2RcvMaxNum = %d\r\n", ret, type, g_2x2RcvMaxNum[1]);
									if((msgCyc == s_2x2_Ctrl.InputMineSysCyc) && (msgCyc == s_2x2_Ctrl.InputPeerSysCyc))
									{
										/*- 更新对系邻机输入数据同步报文周期号 */
										s_2x2_Ctrl.RxInputSysCyc = msgCyc;
										MSCP_LOG_MSG("s_2x2_Ctrl.RxInputSysCyc = %d\r\n", s_2x2_Ctrl.RxInputSysCyc);
									}
									else
									{
										/*- 无处理 */
									}
								}
								else
								{
									/*- 无处理 */
								}
							}
							else
							{
								/*- 无处理 */
								MSCP_LOG_MSG("p_rmt_peer_buf msgCyc = %d, s_2x2_Ctrl.RxInputSysCyc = %d\r\n", msgCyc, s_2x2_Ctrl.RxInputSysCyc);
							}
						}
						else
						{
							/*- 宕机 */
							CM_RE_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_13);
						}
						/*记录暗文日志*/
						(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_RCV_INPUT_STATE,5u,
													sizeof(CM_UINT32),type,
													sizeof(CM_UINT8),(msgCyc >= s_2x2_Ctrl.RxInputSysCyc),
													sizeof(CM_UINT32),msgCyc,
													sizeof(CM_UINT32),s_2x2_Ctrl.RxInputSysCyc,
													sizeof(CM_UINT32),NOW_USED_TIME);
						/*- 返回 */
						break;
					}/* end switch */
				}
				else
				{
					/*- 无处理 */
				}
			}/* end if (0 < rxLen)*/
			else
			{
				/*- 无处理 */
			}
		} while (0 < rxLen);
    }
    else
    {
    	/*时间同步未完成，清空所有2x接收数据*/
		SFM_2x2_ClearRcvMsgQ();
    }
	PFM_LOG_SET_STOPTIMER(TSCP_DARK_NULL);
}

/**
* @brief 输入阶段2x2处理
* @details
* 接收对系输入数据；
* 系内交换和比较；
* 更新热备状态并发送状态信息（主系）。
*/
void SFM_2x2_InputProc(void)
{
    /*- 变量初始化 */
    STRU_2X2_CTRL_T peerCtrl; /* 邻机热备状态 */
    CM_INT32 ret = 0;       /* 临时变量 */
    CM_UINT32 sysCyc = SFM_2x2_GetSysCount();  /* 系统周期号 */
    CM_UINT64 sTick = 0u; /* 起始Tick */
    CM_UINT64 delta_Tick = 0u; /* Tickze增量 */
    CM_UINT64 curTick = 0u; /* 当前Tick */
    CM_UINT32 len = 0u;        /* 临时变量 */
	/*######################## 发送跟随数据（主系）########################*/
    PFM_CFC_Check(33);
	/*- 填写适配层(-1)跟随数据 */
	len = SFM_GetPrtclFollowData(g_TxBaseFollow + 4, (CM_UINT32)(sizeof(g_TxBaseFollow)) - 4u);
	CM_LongToChar(len, g_TxBaseFollow);
	g_TxBaseFollow_len = (CM_INT32)len + 4;
	/*- 填写内网sfp跟随数据 */
	len = SFM_GetSfpPrtclFollowData(g_TxBaseFollow + g_TxBaseFollow_len, (CM_UINT32)(sizeof(g_TxBaseFollow)- g_TxBaseFollow_len - 4u));
	g_TxBaseFollow_len += len;
	/*- 填写平台跟随数据 */
	/*- 填写平台跟随数据 */
	CM_RE_ASSERT(g_TxBaseFollow_len <= ((CM_INT32)sizeof(g_TxBaseFollow) - 12u), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_7, TSCP_DARK_ASSERT_9);/*输出缓冲至少空闲8字节*/
	CM_LongToChar(8u, g_TxBaseFollow + g_TxBaseFollow_len);
	CM_LongToChar(sysCyc, g_TxBaseFollow + g_TxBaseFollow_len + 4u);
	CM_LongToChar(SFM_GetTxSn(), g_TxBaseFollow + g_TxBaseFollow_len + 8u);
	g_TxBaseFollow_len += 12u;
	/* 2取比较后,若为主系执行发送*/
	if(0x55u == g_PFM_Cfg.M_2oo2_Enable)
	{
		s_2x2_BaseFollow_2oo2Check_Send();
	}
	MSCP_LOG_MSG("timecurr 3.1 Input 2x2Send = %lld us\n", NOW_USED_TIME);
    /*########################2x2对系数据接收########################*/
    PFM_CFC_Check(34);
    /*- 接收对系数据 */
    s_2x2_Recv();
    /*- 本系是否非主 */
    if (ENUM_2x2_MASTER != s_2x2_Ctrl.LocalState)
    {
        /*- 记录当前时刻 */
        sTick = CM_GetTick();
        CM_Sleep(2u);
        curTick = CM_GetTick();
        delta_Tick = (CM_UINT64)CM_UNSIGNED_INT_EXP(g_PFM_Cfg.CYC_TIME * CM_UNSIGNED_MILLION / 10u);
        /*- 持续接收对系输入同步数据，尝试(周期时间/5)ms */
        while (curTick < (sTick + delta_Tick))
        {
            /*- 接收对系数据 */
            s_2x2_Recv();
            /*- 是否收到了预期的输入同步数据 */
            if ((s_2x2_Ctrl.RxInputSysCyc >= sysCyc) &&
            	(s_2x2_Ctrl.RxBaseFollowSysCyc >= sysCyc) &&
				(s_2x2_Ctrl.RxBaseFollowSysCyc > 0u))
            {
                /*- 退出循环 */
                break;
            }
            else
            {
            	/*- 无处理 */
            }
            /*- 延时等待 */
            CM_Sleep(2u);
            curTick = CM_GetTick();
        }
    }
    else
    {
    	/*- 无处理 */
    }
    MSCP_LOG_MSG("timecurr 3.2 Input 2x2Send = %lld us\n", NOW_USED_TIME);
    /*########################2x2对系数据交换和比较########################*/
    /*- 是否开启2oo2功能 */
    if (0x55u == g_PFM_Cfg.M_2oo2_Enable)
    {
        /*- 更新控制流状态 */
        PFM_CFC_Check(35);
        /*- 系内同步(状态校验，对系状态报文同步)*/
        s_Ctrl_2oo2Sync(&peerCtrl);

        /*- @alias 系内交换输入数据 */
        PFM_CFC_Check(36);

		/*- 是否需要向邻机发送输入同步数据 */
        /*  如果需要交换对于cpu1的本机数据,相当于cpu2的邻机数据,cpu1的邻机数据,相当于cpu2的本机数据 */
        /*- @alias 系内同步Rx输入信息状态,用来过滤老的输入数据,并且将新的数据进行2oo2交换*/
        SFM_2x2_Input2oo2Exchange(&peerCtrl);
        /*- 跟新输入同步周期号*/
        SFM_2x2_InputSysCycSyn(&peerCtrl);


        /*- 更新控制流状态 */
        PFM_CFC_Check(37);
        /* (这个数据量很大，只在必要时同步) */
        /*- @alias 系内同步Rx跟随数据*/
        ret = SFM_2x2_BaseFollowSyn(&peerCtrl);
        CM_RE_ASSERT(0 == ret, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_7, TSCP_DARK_ASSERT_1);

    }
    else
    {
        /*- 更新控制流状态 */
        PFM_CFC_Check(35);
        PFM_CFC_Check(36);
        PFM_CFC_Check(37);
    }
    /*########################状态机更新########################*/
    PFM_CFC_Check(38);
    /*########################关键数据覆盖########################*/
    PFM_CFC_Check(39);
    /*- 本系是否为离线或备 */
    if ((ENUM_2x2_OFFLINE == s_2x2_Ctrl.LocalState)
        || (ENUM_2x2_SLAVE == s_2x2_Ctrl.LocalState))
    {
    	if ((g_RxBaseFollow_len >= 16) && (s_2x2_Ctrl.RxBaseFollowSysCyc > 0u))/*通过数据长度判断是否有新数据*/
		{
			s_2x2_BaseFollow_Sync();
			/*- 记录本次跟随时间 */
			s_2x2_Ctrl.LastFollowCyc = s_2x2_Ctrl.RxBaseFollowSysCyc;
			MSCP_LOG_MSG("follow cyc = %d->%d\n",s_2x2_Ctrl.LastFollowCyc,sysCyc);
			/*记录暗文日志*/
			(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_BASE_FOLLOW_HANDLE,4u,
										sizeof(CM_UINT8),1u,
										sizeof(CM_UINT32),sysCyc,
										sizeof(CM_UINT32),s_2x2_Ctrl.LastFollowCyc,
										sizeof(CM_UINT32),NOW_USED_TIME);
		}
    	else
    	{
    		MSCP_LOG_MSG("err follow cyc = %d->%d\n",s_2x2_Ctrl.RxBaseFollowSysCyc,sysCyc);
			/*记录暗文日志*/
			(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_BASE_FOLLOW_HANDLE,4u,
										sizeof(CM_UINT8),0u,
										sizeof(CM_UINT32),sysCyc,
										sizeof(CM_UINT32),s_2x2_Ctrl.LastFollowCyc,
										sizeof(CM_UINT32),NOW_USED_TIME);
    	}
    }
    else
	{
		/*- 无处理 */
	}
    /*- 清除待发送的平台跟随数据 */
    g_TxBaseFollow_len = 4;
    CM_LongToChar(0u, g_TxBaseFollow);

    g_RxBaseFollow_len = 0;
    /* @see :: SFM_2x2_OutputProc */
}

/**
* @brief 输出阶段2x2处理
* @param CheckBuf 输出校验报文数组
* @param CheckLen 输出校验报文长度
* @details
* 主系发送/备系接收输出校验报文；
* 接收对系状态；
* 系内交换；
* 输出校验(非主）；
* 更新热备状态并发送状态数据（非主）；
* 生成和发送跟随数据（主系）。
*/
void SFM_2x2_OutputProc(IN const CM_UINT8 *CheckBuf, CM_INT32 CheckLen)
{
    /*- 变量初始化 */
    STRU_2X2_CTRL_T peerCtrl = { 0 };        /* 邻机热备状态 */
    CM_UINT32 sysCyc = SFM_2x2_GetSysCount(); /* 系统周期号 */
    CM_INT32 ret = 0;          /* 临时变量 */
    CM_UINT64 sTick = 0u; /* 起始Tick */
    CM_UINT64 delta_Tick = 0u; /* Tickze增量 */
    CM_UINT64 curTick = 0u; /* 当前Tick */
    ENUM_CM_RETURN retError = ENUM_CM_FALSE;
    CM_UINT32 i = 0u;
    /*- 入参检查 */
    CM_ASSERT(NULL != CheckBuf, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_8, TSCP_DARK_ASSERT_1);
    /*########################发送输出校验########################*/
    PFM_CFC_Check(10);
    /*- 本系是否为主系 */
    if (ENUM_2x2_MASTER == s_2x2_Ctrl.LocalState)
    {
        /*- 发送输出校验帧*/
        SFM_2x2_Send(CheckBuf, (CM_UINT32)CheckLen, ENUM_2x2_MSG_OUTCHECK);
    }
    else
	{
		/*- 无处理 */
	}

    /*########################接收对系报文########################*/
    PFM_CFC_Check(11);
    /*- 接收2x2数据（状态帧、输出校验帧）*/
    /*- 本系是否非主 */
	if (ENUM_2x2_MASTER != s_2x2_Ctrl.LocalState)
	{
		/*- 记录当前时刻 */
		sTick = CM_GetTick();
		curTick = CM_GetTick();
		delta_Tick = (CM_UINT64)CM_UNSIGNED_INT_EXP(g_PFM_Cfg.CYC_TIME * CM_UNSIGNED_MILLION / 10u);
		/*- 持续接收对系输出校验帧 */
		while (curTick < (sTick + delta_Tick))
		{
			/*- 接收对系数据 */
		    s_2x2_Recv();
			/*- 是否收到了预期的输出校验帧  */
			if (s_2x2_Ctrl.RxCheckSysCyc >= sysCyc)
			{
				/*- 退出循环 */
				break;
			}
			else
			{
				/*- 无处理 */
			}
			/*- 延时等待 */
			CM_Sleep(2u);
			curTick = CM_GetTick();
		}
	}
	else
	{
		/*- 无处理 */
	}

    /*########################系内交换########################*/    
	PFM_CFC_Check(12);
    /*- @alias 系内同步(状态校验，对系状态报文同步) */
    if (0x55u == g_PFM_Cfg.M_2oo2_Enable)
    {
        s_Ctrl_2oo2Sync(&peerCtrl);

        /*- @alias 系内同步输出校验帧信息 */
        if (s_2x2_Ctrl.RxCheckSysCyc < peerCtrl.RxCheckSysCyc)
        {
            s_2x2_Ctrl.RxCheckSysCyc = peerCtrl.RxCheckSysCyc;
            s_2x2_Ctrl.RxCheckLen = peerCtrl.RxCheckLen;
            retError = CM_Memset((void*)s_2x2_Ctrl.RxCheckFrame, (CM_UINT8)0u, sizeof(s_2x2_Ctrl.RxCheckFrame),  sizeof(s_2x2_Ctrl.RxCheckFrame));
            CM_RE_ASSERT(ENUM_CM_TRUE == retError, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_8, TSCP_DARK_ASSERT_2);
            (void)CM_Memcpy((void*)s_2x2_Ctrl.RxCheckFrame, sizeof(s_2x2_Ctrl.RxCheckFrame), (void*)peerCtrl.RxCheckFrame, (CM_SIZE_T)(peerCtrl.RxCheckLen));
        }
        else
		{
			/*- 无处理 */
		}
    }
    else
	{
		/*- 无处理 */
	}


    /*######################## 输出校验(非主）########################*/
    PFM_CFC_Check(13);
    /*- 本系是否为备系或离线 */
    if ((ENUM_2x2_SLAVE == s_2x2_Ctrl.LocalState) || (ENUM_2x2_OFFLINE == s_2x2_Ctrl.LocalState))
    {
        /*- 检查输出校验数据是否一致且为最新 */
        if ((sysCyc == s_2x2_Ctrl.RxCheckSysCyc) && (CheckLen == s_2x2_Ctrl.RxCheckLen))
        {
            /*- 进行输出比较 */
			s_2x2_Output_SyncCheck(CheckBuf, CheckLen);
        }
        else
        {
            MSCP_LOG_MSG("2x2Follow:[%d,%d,%d,%d][%d,%d][%d,%d]\n",
                sysCyc, s_2x2_Ctrl.RxInputSysCyc, s_2x2_Ctrl.LastFollowCyc, s_2x2_Ctrl.RxCheckSysCyc,
                s_2x2_Ctrl.RxBaseFollowSysCyc,s_2x2_Ctrl.RxAppFollowSysCyc,CheckLen, s_2x2_Ctrl.RxCheckLen);
        }
    }
    else
	{
		/*- 无处理 */
	}
    PFM_CFC_Check(14);
    /*######################## 更新热备状态并发送状态数据（非主）########################*/
    /*- 暗文记录二乘通信状态(输出微周期后平台周期结束) */
    SFM_2x2_Eth422StateDark();
}

/**
* @brief 应用跟随数据接收
* @param sysCyc 系统周期号(0~0xFFFF) stat 本机热备状态（0~4)
* @details
* 接收主系发送的应用跟随数据
*/
static void SFM_2x2_RecvAppFollowData(CM_UINT32 sysCyc, ENUM_2x2_STATE_T stat)
{
    CM_UINT64 delta_Tick = 0u;
    CM_UINT64 curTick = 0u; /* 当前时刻 */
    CM_UINT64 sTick[3] = {0u}; /* 起始Tick */
    CM_INT32 ret = 0;       /* 返回值 */
    STRU_2X2_CTRL_T peerCtrl = { 0 }; /* 邻机2x2状态 */
    if(ENUM_2x2_SLAVE == stat)
    {
    	delta_Tick = (CM_UINT64)CM_UNSIGNED_INT_EXP(g_PFM_Cfg.CYC_TIME * CM_UNSIGNED_MILLION/10u);
    }
    else
    {
    	delta_Tick = (CM_UINT64)CM_UNSIGNED_INT_EXP(g_PFM_Cfg.CYC_TIME * CM_UNSIGNED_MILLION/5u);
    }

    sTick[0] = CM_GetTick();
    /*- 持续接收对系输入同步数据，尝试(周期时间/10)ms */
    do
    {
        /*- 接收2x2数据 */
        /*- 是否收到了应用跟随数据 */
        s_2x2_Recv();
        if (s_2x2_Ctrl.RxAppFollowSysCyc >= sysCyc)
        {
            /*- 返回 */
            MSCP_LOG_MSG("rx app follow success\n");
            /*- 跳出 */
            break;
        }
        else
        {
        	/*- 无处理 */
        }
        CM_Sleep(2u);
        curTick = CM_GetTick();
    } while (curTick < (sTick[0] + delta_Tick));
    sTick[1] = CM_GetTick();

	if(0x55u == g_PFM_Cfg.M_2oo2_Enable)
	{
		/*- 2oo2同步本系热备状态 */
		s_Ctrl_2oo2Sync(&peerCtrl);
		/*- 是否需要向邻机发送应用同步数据 */
		if (s_2x2_Ctrl.RxAppFollowSysCyc > peerCtrl.RxAppFollowSysCyc)
		{
			/*- 自己是否是备系*/
			if(ENUM_2x2_SLAVE == stat)
			{
				/*- 发送跟随数据的CRC和长度*/
				MSCP_LOG_MSG("A-B:g_RxAppFollowCrc_len:%lld\n",g_RxAppFollowCrc_len);
				ret = SFM_2oo2_Exchange_Currency(g_RxAppFollowCrc, g_RxAppFollowCrc_len, g_RxAppFollowCrc, 0u, ENUM_2oo2_END_EX);
			}
			else
			{
				/*- 发送全部应用跟随数据*/
				MSCP_LOG_MSG("A-B:g_RxAppFollow_len:%lld\n",g_RxAppFollow_len);
				ret = SFM_2oo2_Exchange_Currency(g_RxAppFollow, g_RxAppFollow_len, g_RxAppFollow, 0u, ENUM_2oo2_END_EX);
			}

			CM_RE_ASSERT(0 == ret, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_9, TSCP_DARK_ASSERT_1);
		}
		/*- 是否需要从邻机接收应用同步数据 */
		else if (s_2x2_Ctrl.RxAppFollowSysCyc < peerCtrl.RxAppFollowSysCyc)
		{
			/*- 自己是否是备系*/
			if(ENUM_2x2_SLAVE == stat)
			{
				/*- 接收应用跟随数据的CRC和长度*/
				MSCP_LOG_MSG("B-A:g_RxAppFollowCrc_len:%lld\n",g_RxAppFollowCrc_len);
				g_RxAppFollowCrc_len = SFM_2oo2_Exchange_Currency(g_RxAppFollowCrc, 0, g_RxAppFollowCrc, sizeof(g_RxAppFollowCrc), ENUM_2oo2_END_EX);
			}
			else
			{
				/*- 接收全部应用跟随数据*/
				MSCP_LOG_MSG("B-A:g_RxAppFollow_len:%lld\n",g_RxAppFollow_len);
				g_RxAppFollow_len = SFM_2oo2_Exchange_Currency(g_RxAppFollow, 0, g_RxAppFollow, sizeof(g_RxAppFollow), ENUM_2oo2_END_EX);
			}
			/*- 更新结接收应用跟随数据周期号*/
			s_2x2_Ctrl.RxAppFollowSysCyc = peerCtrl.RxAppFollowSysCyc;
		}
		else
		{
			/*- 无处理 */
		}
	}
	else
	{
		/*- 无处理 */
	}
	sTick[2] = CM_GetTick();
	MSCP_LOG_MSG("2xRecv over time = %lld ,2oo2 time = %lld\n",(sTick[1] - sTick[0]) / 1000u, (sTick[2] - sTick[1]) / 1000u);
}

/**
* @brief 周期末处理
*/
void SFM_2x2_EndProc(void)
{
    /*- 变量初始化 */
    CM_UINT32 sysCyc = SFM_2x2_GetSysCount(); /* 系统周期号 */
    ENUM_2x2_STATE_T stat = SFM_2x2_GetLocal2x2State(); /* 本机热备状态 */
    ENUM_CM_RETURN retFollowUp = ENUM_CM_FALSE;
    CM_UINT64 curTickTest[10] = {0u}; /* 当前时刻 */

    switch(stat)
    {
    case ENUM_2x2_MASTER:
    	curTickTest[0] = CM_GetTick();
    	if(ENUM_2x2_SLAVE == SFM_2x2_GetPartner2x2State())
    	{
            /*- 发送跟随数据 */
    		SFM_2x2_Send(g_TxAppFollow, (CM_UINT32)12, ENUM_2x2_MSG_APP_FOLLOW_CRC);
            MSCP_LOG_MSG("Iam master partner is slave send appfollowcrc\n");
    	}
    	else
    	{
    		SFM_2x2_Send(g_TxAppFollow + 8, (CM_UINT32)g_TxAppFollow_len, ENUM_2x2_MSG_APP_FOLLOW);
        	MSCP_LOG_MSG("Iam master partner is offline send appfollow\n");
    	}
    	curTickTest[1] = CM_GetTick();
    	break;
    case ENUM_2x2_SLAVE:
    	SFM_2x2_RecvAppFollowData(sysCyc, stat);
    	curTickTest[0] = CM_GetTick();
    	if (s_2x2_Ctrl.RxAppFollowSysCyc >= sysCyc)
    	{
			s_2x2_AppFollow_SyncCheck();
    	}
    	else
    	{
    		/*没有收到数据 将离线*/
    		s_2x2_Ctrl.AppFollowCmpFlag = 1u;
    	}
    	curTickTest[1] = CM_GetTick();
    	break;
    case ENUM_2x2_OFFLINE:
    case ENUM_2x2_PRE_MASTER:
    	SFM_2x2_RecvAppFollowData(sysCyc, stat);
    	curTickTest[0] = CM_GetTick();
		/* 应用跟随数据覆盖 */
		/*- 是否收到了最新的应用跟随数据 */
		if (s_2x2_Ctrl.RxAppFollowSysCyc >= sysCyc)
		{
			/*- 调用应用API覆盖应用关键数据 */
			retFollowUp = APP_API_FollowUp(g_RxAppFollow, (CM_UINT32)g_RxAppFollow_len);
			CM_RE_ASSERT(ENUM_CM_TRUE == retFollowUp, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_9, TSCP_DARK_ASSERT_2);
			s_2x2_Ctrl.AppFollowCmpFlag = 0u;
		}
		else
		{
			s_2x2_Ctrl.AppFollowCmpFlag = 1u;
		}
    	curTickTest[1] = CM_GetTick();
		break;
    default:
    	break;
    }
    MSCP_LOG_MSG("slef stata is %d use time = %lld\n",stat,(curTickTest[1] - curTickTest[0]) / 1000u);
    /*更新周期号*/
	if ((s_2x2_Ctrl.SysCycSync >= sysCyc) && (ENUM_2x2_MASTER != stat))
	{
		g_MSCP_SysCount = s_2x2_Ctrl.SysCycSync;
	}
	else
	{
		;
	}
	/*记录暗文日志*/
	(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_APP_FOLLOW_HANDLE,2u,
								sizeof(CM_UINT32),s_2x2_Ctrl.RxAppFollowSysCyc,
								sizeof(CM_UINT32),(curTickTest[1] - curTickTest[0])/1000u);
    /*主线程状态同步到应用*/
    s_2x2_Ctrl.LastLocalState = s_2x2_Ctrl.LocalState;
    s_2x2_Ctrl.LastPartnerState = s_2x2_Ctrl.PartnerState;
    (void)SFM_2x2_SyncIoInput(s_2x2_InputIoState,40u);
    /*- 清空待发送的应用跟随数据，待应用下周期填写 */
    g_TxAppFollow_len = 4;
    CM_LongToChar(0u, g_TxAppFollow);
}

/**
* @brief 系内热备状态同步
* @param pPeerCtrl 邻机热备信息
* details
* 系内交换热备信息；
* 校验2oo2双机的热备状态是否一致；
* 系内同步对系连接状态；
* 系内同步收到的状态帧信息。
*/
static void s_Ctrl_2oo2Sync(OUT STRU_2X2_CTRL_T *pPeerCtrl)
{
	/*- 变量初始化 */
    CM_INT32 rxLen = 0;
    ENUM_CM_RETURN retError = ENUM_CM_FALSE;
    /*- 入参检查 */
    CM_ASSERT(NULL != pPeerCtrl, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_10);
    /* 本机自检状态也需要同步到邻机 */
    /*- 系内交换热备状态信息 */
    retError = CM_Memset(pPeerCtrl, (CM_UINT8)0, sizeof(STRU_2X2_CTRL_T), sizeof(STRU_2X2_CTRL_T));
    CM_RE_ASSERT(ENUM_CM_TRUE == retError, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_1);
    rxLen = SFM_2oo2_Exchange_Currency((CM_UINT8*)&s_2x2_Ctrl, (CM_INT32)sizeof(s_2x2_Ctrl), (CM_UINT8*)pPeerCtrl, (CM_UINT32)sizeof(STRU_2X2_CTRL_T), ENUM_2oo2_INPUT_MS);
    CM_RE_ASSERT(rxLen == (CM_INT32)sizeof(s_2x2_Ctrl), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_2);
    /*- 校验2oo2双机的热备状态是否一致 */
    CM_RE_ASSERT(s_2x2_Ctrl.LocalState == pPeerCtrl->LocalState, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_3);
    CM_RE_ASSERT(s_2x2_Ctrl.PartnerState == pPeerCtrl->PartnerState, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_4);

    CM_RE_ASSERT(s_2x2_Ctrl.LastFollowCyc == pPeerCtrl->LastFollowCyc, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_5);
	CM_RE_ASSERT(s_2x2_Ctrl.LastCheckOKCount == pPeerCtrl->LastCheckOKCount, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_6);
	CM_RE_ASSERT(s_2x2_Ctrl.LastLocalState == pPeerCtrl->LastLocalState, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_7);
	CM_RE_ASSERT(s_2x2_Ctrl.LastPartnerState == pPeerCtrl->LastPartnerState, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_8);
	CM_RE_ASSERT(s_2x2_Ctrl.OutPutCheckFailFlag == pPeerCtrl->OutPutCheckFailFlag, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_9);
	CM_RE_ASSERT(s_2x2_Ctrl.AppFollowCmpFlag == pPeerCtrl->AppFollowCmpFlag, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_10, TSCP_DARK_ASSERT_12);
}

/**
* @brief 获取本系热备状态
* @return 本系热备状态
* - ENUM_2x2_OFFLINE 离线
* - ENUM_2x2_PRE_MASTER 预升主
* - ENUM_2x2_MASTER 主系
* - ENUM_2x2_SLAVE 备系
* @details
* 所有状态下周期应用逻辑都会被执行
* 只有“主系”状态下本机的输出才会被真实输出
* 在“离线”和“备系”状态下且本周期收到有效跟随数据时，
* 将在周期应用逻辑执行之前进行跟随数据覆盖。
* @see :: APP_API_FollowUp
*/
ENUM_2x2_STATE_T SFM_2x2_GetLocal2x2State(void)
{
	/*每次查询控制主备指示灯*/
	if(ENUM_2x2_MASTER == s_2x2_Ctrl.LocalState)
	{
		DFM_ledMS(1u);
	}
	else if(ENUM_2x2_SLAVE == s_2x2_Ctrl.LocalState)
	{
		DFM_ledMS(3u);
	}
	else
	{
		DFM_ledMS(0u);
	}
    /*- 输出本系热备状态 */
    return CM_ATOMIC_LOAD(&s_2x2_Ctrl.LocalState);
}

/**
* @brief 获取对系热备状态
* @return 对系热备状态
* - ENUM_2x2_SHUTDOWN 宕机
* - ENUM_2x2_OFFLINE 离线
* - ENUM_2x2_PRE_MASTER 预升主
* - ENUM_2x2_MASTER 主系
* - ENUM_2x2_SLAVE 备系
* @details
* 与对系通信中断时默认对系状态为“宕机”
*/
ENUM_2x2_STATE_T SFM_2x2_GetPartner2x2State(void)
{
    /*- 输出对系热备状态 */
    return CM_ATOMIC_LOAD(&s_2x2_Ctrl.PartnerState);
}


/*
* @brief 获取上一周期的本系热备状态
* @return 本系热备状态
* - ENUM_2x2_OFFLINE 离线
* - ENUM_2x2_PRE_MASTER 预升主
* - ENUM_2x2_MASTER 主系
* - ENUM_2x2_SLAVE 备系
* @note
* 宕机状态下应用逻辑不会被执行，
* 所以应用本函数不可能返回“宕机”。
* 其它状态下周期应用逻辑都会被执行，
* 但只有“主系”状态下本机的输出才会被真实输出，
* 在“离线”和“备系”状态下且本周期收到有效跟随数据时，
* 将在周期应用逻辑执行之前进行跟随数据覆盖。
*/
ENUM_2x2_STATE_T SFM_2x2_GetLastLocal2x2State(void)
{
	return CM_ATOMIC_LOAD(&s_2x2_Ctrl.LastLocalState);
}

/**
* @brief 获取对系上一周期的热备状态
* @return 对系热备状态
* - ENUM_2x2_SHUTDOWN 宕机
* - ENUM_2x2_OFFLINE 离线
* - ENUM_2x2_PRE_MASTER 预升主
* - ENUM_2x2_MASTER 主系
* - ENUM_2x2_SLAVE 备系
* @note
* 与对系通信中断时默认对系状态为“宕机”
*/
ENUM_2x2_STATE_T SFM_2x2_GetLastPartner2x2State(void)
{
	return CM_ATOMIC_LOAD(&s_2x2_Ctrl.LastPartnerState);
}

/**
* @brief 设置跟随数据
* @param Data 跟随数据数组
* @param Len 跟随数据长度
* @return 函数执行结果
* - 1 成功
* - 0 失败(输入非法)
* @details
* 本系为主系时，应用应当每周期设置一次跟随数据。
* 跟随数据量最大为1024*1000字节。
* (本系非主时的调用、单周期多次调用，都将被return 0)
* @see :: APP_API_FollowUp
*/
CM_UINT8 SFM_2x2_SetFollowData(IN const CM_UINT8 Data[], IN CM_UINT32 Len)
{
    /*- 变量初始化 */
    CM_UINT8 rt = 0u; /* 函数返回值 */
    CM_UINT32 crc = 0u;
    /*- 检查输入是否合法 */
    if ((NULL != Data)
        && (Len < (CM_UINT32)(MSCP_FOLLOW_BUFF_SIZE))
        && (0u < Len))
    {
    	/*- 保存应用跟随数据 */
    	g_TxAppFollow_len = (CM_INT32)CM_UNSIGNED_INT_EXP(Len + 4u);
    	crc = CM_Crc32(Data, Len);
    	CM_LongToChar(crc, g_TxAppFollow);
		/* 预留4字节记录另一CPU的CRC */
    	CM_LongToChar(Len, g_TxAppFollow + 8);
    	(void)CM_Memcpy((void*)(g_TxAppFollow + 12), sizeof(g_TxAppFollow) - 12u, Data, (CM_SIZE_T)Len);
    	rt = 1u;
    }
    else
	{
    	/*- 无处理 */
    	MSCP_LOG_MSG("App SetFollowData failed Len = %d\n",Len);
	}
    CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_2X2_APPSET_FOLLOW,4u,&Len);
    /*- 返回执行结果 */
    return rt;
}

/**
* @brief 获取系统周期号
* @return 当前的系统周期号
* @details
* 一个固定周期自增的周期号;
* 对于2x2系统，2x2双系的周期号会被自动同步到与主系一致
*/
CM_UINT32 SFM_2x2_GetSysCount(void)
{
    /*- 输出系统周期号 */
    return g_MSCP_SysCount;
}
/**
* @brief 更新本周期通信状态通用函数
* @param ComOKCountBuf 更新状态通信ok次数数组
* @param ComOKCount 通信OK次数
* @return 无
* @details
* 更新本周期通信状态，将历史状态信息移位保存
*/
void MSCP_UpData_2X_This_ComState(STRU_2X2_COM_STATE_RECORD_T *ComOKCount,CM_UINT32 SysCyc,CM_UINT8 MicroCyc)
{
	CM_UINT8 i = 0u; /* 循环次数 */
	if(NULL != ComOKCount)
	{
		/*向前滑动*/
		for(i = 0u; i < MSCP_2X2_COM_THIS_STATE_NUM;i++)
		{
			ComOKCount[i].SysCyc = ComOKCount[i+1].SysCyc;
			ComOKCount[i].MicroCyc = ComOKCount[i+1].MicroCyc;
		}
		/*更新本周期次数*/
		ComOKCount[MSCP_2X2_COM_THIS_STATE_NUM].SysCyc = SysCyc;
		ComOKCount[MSCP_2X2_COM_THIS_STATE_NUM].MicroCyc = MicroCyc;
	}
	else
	{
		CM_ASSERT(0,  SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_11, TSCP_DARK_ASSERT_1);
	}
}
/**
* @brief 获取通信断开次数通用函数
* @param ComOKCountBuf 更新状态通信ok次数数组
* @param BeforeCycNum 查询前几个周期序号，例如：0代表本周期，
* @return 通信断开的次数
* @details
* 可向前查询通信正常次数周期号
*/
CM_UINT32 MSCP_Get_2X_DisCom_Count(STRU_2X2_COM_STATE_RECORD_T *ComOKCount,CM_UINT8 BeforeCycNum)
{
	CM_UINT32 val = 0u;
	CM_INT32 SysCycDval = 0u;
	CM_INT8  MicroCycDval = 0u;
	if((NULL != ComOKCount) && (BeforeCycNum <= MSCP_2X2_COM_THIS_STATE_NUM))
	{
		/*计算公式：B、A主周期号，b、a微周期号。|(B-A)xn-|(b-a)||*/
		SysCycDval = (s_2x2_state_Ctrl.SysCyc - ComOKCount[MSCP_2X2_COM_THIS_STATE_NUM - BeforeCycNum].SysCyc) * s_2x2_thread_Ctrl.number_Cyc;
		MicroCycDval = CM_ABS(s_2x2_state_Ctrl.MicroCyc - ComOKCount[MSCP_2X2_COM_THIS_STATE_NUM - BeforeCycNum].MicroCyc);
		val = CM_ABS(SysCycDval - MicroCycDval);
	}
	else
	{
		CM_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_12, TSCP_DARK_ASSERT_1);
	}
	return val;
}
/**
* @brief 获取通信状态
* @param ComOKCountBuf 更新状态通信ok次数数组
* @param BeforeCycNum 查询前几个周期序号，例如：0代表本周期，
* @return ENUM_CM_TRUE = 0x55 成功
		  ENUM_CM_FALSE = 0xAA 失败
* @details
*可向前查询通信状态
*/
ENUM_CM_RETURN MSCP_Get_2X_Com_State(STRU_2X2_COM_STATE_RECORD_T *ComOKCount,CM_UINT8 BeforeCycNum)
{
	ENUM_CM_RETURN rtnval = ENUM_CM_FALSE;
	CM_UINT32 Cycval = 0u;
	CM_ASSERT(NULL != ComOKCount, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_13, TSCP_DARK_ASSERT_1);
	Cycval = MSCP_Get_2X_DisCom_Count(ComOKCount,BeforeCycNum);
	/*周期通信成功的标志,预测差值，计算前几个周期的数据*/
	if(BeforeCycNum == Cycval)
	{
		rtnval = ENUM_CM_TRUE;
	}
	else
	{
		rtnval = ENUM_CM_FALSE;
	}
	return rtnval;
}
/**
* @brief 获取模糊通信状态
* @param ComOKCountBuf 更新状态通信ok次数数组
* @return CM_TRUE 成功
		  CM_FALSE 失败
*/
CM_BOOL MSCP_Get_2X_VagueCom_State(STRU_2X2_COM_STATE_RECORD_T *ComOKCount)
{
	CM_UINT8 i = 0u;
	CM_ASSERT(NULL != ComOKCount, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_15, TSCP_DARK_ASSERT_1);
	/*判断主周期号，本周期只要收到同步数据即返回成功*/
	for(i = 0;i <= MSCP_2X2_COM_THIS_STATE_NUM;i++)
	{
		if(s_2x2_state_Ctrl.SysCyc == ComOKCount[i].SysCyc)
		{
			return CM_TRUE;
		}
	}
	return CM_FALSE;
}
/**
* @brief 和邻机交换从对系获得的输入数据
* @param pPeerCtrl:邻机状态  取值范围:非空
* @return 无
*/
static void SFM_2x2_Input2oo2Exchange(STRU_2X2_CTRL_T *peerCtrl)
{
	/*- 变量初始化 */
	CM_UINT32 i = 0u;
	CM_INT32 len = 0;

	if (g_PFM_Cfg.CPU_ID == 1u)
	{
		/*- @alias 系内交换输入数据 */
		for (i = 1u; i <= g_2x2oo2_data_num; i++)
		{
			if(CM_TRUE == g_2x2oo2_rx[g_2x2oo2_base][i].b_2x2_Enable)
			{
				MSCP_LOG_MSG("SFM_2x2_Input2oo2Exchange-CPU1[%d]:[M0:%d,P1:%d][M1:%d,P0:%d]\r\n",i,s_2x2_Ctrl.InPutDoublePassLen[i][0],peerCtrl->InPutDoublePassLen[i][1],s_2x2_Ctrl.InPutDoublePassLen[i][1],peerCtrl->InPutDoublePassLen[i][0]);
				/*本机数据交互*/
				if(s_2x2_Ctrl.InPutDoublePassLen[i][0] < peerCtrl->InPutDoublePassLen[i][1])
				{
					/*接收对方数据，自己发送长度为0*/
					g_2x2oo2_rx[g_2x2oo2_base][i].rmt_mine_len = SFM_2oo2_Exchange_Currency(
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_mine_buf,
						0,
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_mine_buf,
						g_2x2oo2_rx[g_2x2oo2_base][i].buf_size,
						ENUM_2oo2_INPUT_EX);
				}
				else if(s_2x2_Ctrl.InPutDoublePassLen[i][0] > peerCtrl->InPutDoublePassLen[i][1])
				{
					/*- 向邻机发送数据，本机不接收，传入接收长度为0*/
					len = SFM_2oo2_Exchange_Currency(
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_mine_buf,
						g_2x2oo2_rx[g_2x2oo2_base][i].rmt_mine_len,
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_mine_buf,
						0,
						ENUM_2oo2_INPUT_EX);
					CM_RE_ASSERT((0 == len), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_14, TSCP_DARK_ASSERT_1);
				}
				else
				{
					/*等于不交互，包括0*/
				}
				/*邻机数据交互*/
				if(s_2x2_Ctrl.InPutDoublePassLen[i][1] < peerCtrl->InPutDoublePassLen[i][0])
				{
					/*接收对方数据，自己发送长度为0*/
					g_2x2oo2_rx[g_2x2oo2_base][i].rmt_peer_len = SFM_2oo2_Exchange_Currency(
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_peer_buf,
						0,
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_peer_buf,
						g_2x2oo2_rx[g_2x2oo2_base][i].buf_size,
						ENUM_2oo2_INPUT_EX);
				}
				else if(s_2x2_Ctrl.InPutDoublePassLen[i][1] > peerCtrl->InPutDoublePassLen[i][0])
				{
					/*- 向邻机发送数据，本机不接收，传入接收长度为0*/
					len = SFM_2oo2_Exchange_Currency(
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_peer_buf,
						g_2x2oo2_rx[g_2x2oo2_base][i].rmt_peer_len,
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_peer_buf,
						0,
						ENUM_2oo2_INPUT_EX);
					CM_RE_ASSERT((0 == len), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_14, TSCP_DARK_ASSERT_1);
				}
				else
				{
					/*等于不交互，包括0*/
				}
			}
			else
			{

			}
		}
	}
	else
	{
		/*- @alias 系内交换输入数据 */
		for (i = 1u; i <= g_2x2oo2_data_num; i++)
		{
			if(CM_TRUE == g_2x2oo2_rx[g_2x2oo2_base][i].b_2x2_Enable)
			{
				MSCP_LOG_MSG("SFM_2x2_Input2oo2Exchange-CPU2[%d]:[M1:%d,P0:%d][M0:%d,P1:%d]\r\n",i,s_2x2_Ctrl.InPutDoublePassLen[i][1],peerCtrl->InPutDoublePassLen[i][0],s_2x2_Ctrl.InPutDoublePassLen[i][0],peerCtrl->InPutDoublePassLen[i][1]);
				/*邻机数据交互*/
				if(peerCtrl->InPutDoublePassLen[i][0] < s_2x2_Ctrl.InPutDoublePassLen[i][1])
				{
					/*- 向邻机发送数据，本机不接收，传入接收长度为0*/
					len = SFM_2oo2_Exchange_Currency(
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_peer_buf,
						g_2x2oo2_rx[g_2x2oo2_base][i].rmt_peer_len,
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_peer_buf,
						0,
						ENUM_2oo2_INPUT_EX);
					CM_RE_ASSERT((0 == len), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_14, TSCP_DARK_ASSERT_1);

				}
				else if(peerCtrl->InPutDoublePassLen[i][0] > s_2x2_Ctrl.InPutDoublePassLen[i][1])
				{
					/*接收对方数据，自己发送长度为0*/
					g_2x2oo2_rx[g_2x2oo2_base][i].rmt_peer_len = SFM_2oo2_Exchange_Currency(
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_peer_buf,
						0,
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_peer_buf,
						g_2x2oo2_rx[g_2x2oo2_base][i].buf_size,
						ENUM_2oo2_INPUT_EX);
				}
				else
				{
					/*等于不交互，包括0*/
				}
				/*本机数据交互*/
				if(peerCtrl->InPutDoublePassLen[i][1] < s_2x2_Ctrl.InPutDoublePassLen[i][0])
				{
					/*- 向邻机发送数据，本机不接收，传入接收长度为0*/
					len = SFM_2oo2_Exchange_Currency(
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_mine_buf,
						g_2x2oo2_rx[g_2x2oo2_base][i].rmt_mine_len,
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_mine_buf,
						0,
						ENUM_2oo2_INPUT_EX);
					CM_RE_ASSERT((0 == len), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_14, TSCP_DARK_ASSERT_1);
				}
				else if(peerCtrl->InPutDoublePassLen[i][1] > s_2x2_Ctrl.InPutDoublePassLen[i][0])
				{
					/*接收对方数据，自己发送长度为0*/
					g_2x2oo2_rx[g_2x2oo2_base][i].rmt_mine_len = SFM_2oo2_Exchange_Currency(
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_mine_buf,
						0,
						g_2x2oo2_rx[g_2x2oo2_base][i].p_rmt_mine_buf,
						g_2x2oo2_rx[g_2x2oo2_base][i].buf_size,
						ENUM_2oo2_INPUT_EX);
				}
				else
				{
					/*等于不交互，包括0*/
				}

			}
			else
			{

			}
		}
	}
	/*- 清空所有通道长度记录*/
	(void)CM_Memset(s_2x2_Ctrl.InPutDoublePassLen,0,sizeof(s_2x2_Ctrl.InPutDoublePassLen),sizeof(s_2x2_Ctrl.InPutDoublePassLen));
	/*记录暗文日志*/
	(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_INPUT_SYNC_SIZE,2u,
								sizeof(CM_UINT32),g_2x2oo2_rx[g_2x2oo2_base][2].rmt_mine_len,
								sizeof(CM_UINT32),g_2x2oo2_rx[g_2x2oo2_base][2].rmt_peer_len);
}
/**
* @brief 判断2x422以及以太网的通信状况并且填写暗文日志
*/
static void SFM_2x2_Eth422StateDark(void)
{
	/*- 变量初始化 */
	union union_state
	{
		CM_UINT8 state;
		struct byte
		{
			CM_UINT8 bit1:1;
			CM_UINT8 bit2:1;
			CM_UINT8 bit3:1;
			CM_UINT8 bit4:1;
			CM_UINT8 bit5:4;
		}stru_state;
	}u_state;
	CM_UINT8 state2oo2 = 0x01;
	CM_UINT8 cpuId = PFM_CFG_GetCpuID();
	/*- 如果是cpu1*/
	if(1u == cpuId)
	{
		u_state.stru_state.bit1 = 0x01 & (s_2x2_Ctrl.MineComState);
		u_state.stru_state.bit2 = 0x01 & (s_2x2_Ctrl.PeerComState);
		u_state.stru_state.bit3 = 0x01 & (s_2x2_Ctrl.MineUartState);
		u_state.stru_state.bit4 = 0x01 & (s_2x2_Ctrl.PeerUartState);
		u_state.stru_state.bit5 = 0;
	}
	else
	{
		u_state.stru_state.bit1 = 0x01 & (s_2x2_Ctrl.PeerComState);
		u_state.stru_state.bit2 = 0x01 & (s_2x2_Ctrl.MineComState);
		u_state.stru_state.bit3 = 0x01 & (s_2x2_Ctrl.PeerUartState);
		u_state.stru_state.bit4 = 0x01 & (s_2x2_Ctrl.MineUartState);
		u_state.stru_state.bit5 = 0;
	}
	/*- 写入2乘的422eth通信状况至暗文队列 */
	(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_2X2ETH422, 1U, &u_state.state);
	/*- 预留2取eth spi通信状况至暗文队列*/
	(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_2OO2ETHSPI, 1U, &state2oo2);
}

/**
* @brief 设置本系热备状态
* @param localState 本系的热备状态  取值范围：0~4
* @details
* 0, 宕机
* 1, 离机
* 2, 预升主
* 3, 主系
* 4, 备系
*/
void SFM_2x2_SetLocal2x2State(ENUM_2x2_STATE_T localState)
{
	/*- 设置本系热备状态  */
	s_2x2_Ctrl.LocalState = localState;
}
/**
* @brief 判断当前周期是否与对系主机通信中断
* @return 中断返回1，正常返回0
*/
CM_UINT8 SFM_2x2_GetWithPeer_Com_State(void)
{
    CM_UINT8 ret = 0;
    /**容忍一个周期判断通信中断*/
	if ((CM_FALSE == s_2x2_Ctrl.MineComState)  &&
		(CM_FALSE == s_2x2_Ctrl.PeerComState)  &&
		(CM_FALSE == s_2x2_Ctrl.MineUartState) &&
		(CM_FALSE == s_2x2_Ctrl.PeerUartState))
	{
        ret = 1;
    }
    else
    {
        ret = 0;
    }
    return ret;
}

/**
* @brief 判断当前周期本系cpu是否与对系交换机通信中断
* @return 中断返回1，正常返回0
*/
CM_UINT8 SFM_2x2_GetWithESB_Mine_Com_State(void)
{
    CM_UINT8 ret = 0;
    /**容忍一个周期判断通信中断,交换机重启，以太网断开*/
	if (CM_FALSE == s_2x2_Ctrl.MineComState)
	{
        ret = 1;
    }
    else
    {
        ret = 0;
    }
    return ret;
}

/**
* @brief 判断当前周期邻系cpu是否与对系交换机通信中断
* @return 中断返回1，正常返回0
*/
CM_UINT8 SFM_2x2_GetWithESB_Peer_Com_State(void)
{
    CM_UINT8 ret = 0;
    /**容忍一个周期判断通信中断,交换机重启，以太网断开*/
	if (CM_FALSE == s_2x2_Ctrl.PeerComState)
	{
        ret = 1;
    }
    else
    {
        ret = 0;
    }
    return ret;
}
/**
* @brief 判断当前是否满足至少一个以太网和任一通道的条件
* @return 中断返回1，正常返回0
*/
CM_UINT8 SFM_2x2_Get_LeastDoubleCom_State(void)
{
    CM_UINT8 ret = 0u;
	/*是否满足至少一个以太网和任一通道*/
	if(((CM_TRUE == s_2x2_Ctrl.MineComState) &&
		(CM_TRUE == s_2x2_Ctrl.PeerComState)) ||
	   ((CM_TRUE == s_2x2_Ctrl.MineComState) &&
		(CM_TRUE == s_2x2_Ctrl.MineUartState)) ||
	   ((CM_TRUE == s_2x2_Ctrl.MineComState) &&
		(CM_TRUE == s_2x2_Ctrl.PeerUartState)) ||
	   ((CM_TRUE == s_2x2_Ctrl.PeerComState) &&
		(CM_TRUE == s_2x2_Ctrl.MineUartState)) ||
	   ((CM_TRUE == s_2x2_Ctrl.PeerComState) &&
		(CM_TRUE == s_2x2_Ctrl.PeerUartState)))
	{
		ret = 0u;
	}
	else
	{
		ret = 1u;
	}
	return ret;
}
/**
* @brief 主线程同步到应用的两系输入io状态
* @param ioInput 接收缓冲区  取值范围：非空
* @return ENUM_CM_TRUE 成功，ENUM_CM_FALSE 失败
*/
ENUM_CM_RETURN SFM_2x2_SyncIoInput(OUT CM_UINT8* ioInput,CM_UINT16 size)
{
	/*- 变量初始化 */
	ENUM_CM_RETURN ret = ENUM_CM_FALSE;
	CM_UINT8 cpu_id = 0u;
	/*- 入参如果为空 */
	if((NULL == ioInput) || (size < 40u))
	{
		/*- 无处理 */
	}
	else
	{
		/*- 获取两系2取后的输入io状态 */
		cpu_id = ((g_PFM_Cfg.BOARD_ID - 1u) * 2u) + g_PFM_Cfg.CPU_ID;
		switch(cpu_id)
		{
			case 1:
				(void)CM_Memcpy(&ioInput[0],10,s_2x2_Ctrl.MineInputIoState,10);
				(void)CM_Memcpy(&ioInput[10],10,s_2x2_Ctrl.PeerInputIoState,10);
				(void)CM_Memcpy(&ioInput[20],10,s_2x2_Ctrl.RmtMineInputIoState,10);
				(void)CM_Memcpy(&ioInput[30],10,s_2x2_Ctrl.RmtPeerInputIoState,10);
				ret = ENUM_CM_TRUE;
				break;
			case 2:
				(void)CM_Memcpy(&ioInput[0],10,s_2x2_Ctrl.PeerInputIoState,10);
				(void)CM_Memcpy(&ioInput[10],10,s_2x2_Ctrl.MineInputIoState,10);
				(void)CM_Memcpy(&ioInput[20],10,s_2x2_Ctrl.RmtPeerInputIoState,10);
				(void)CM_Memcpy(&ioInput[30],10,s_2x2_Ctrl.RmtMineInputIoState,10);
				ret = ENUM_CM_TRUE;
				break;
			case 3:
				(void)CM_Memcpy(&ioInput[0],10,s_2x2_Ctrl.RmtMineInputIoState,10);
				(void)CM_Memcpy(&ioInput[10],10,s_2x2_Ctrl.RmtPeerInputIoState,10);
				(void)CM_Memcpy(&ioInput[20],10,s_2x2_Ctrl.MineInputIoState,10);
				(void)CM_Memcpy(&ioInput[30],10,s_2x2_Ctrl.PeerInputIoState,10);
				ret = ENUM_CM_TRUE;
				break;
			case 4:
				(void)CM_Memcpy(&ioInput[0],10,s_2x2_Ctrl.RmtPeerInputIoState,10);
				(void)CM_Memcpy(&ioInput[10],10,s_2x2_Ctrl.RmtMineInputIoState,10);
				(void)CM_Memcpy(&ioInput[20],10,s_2x2_Ctrl.PeerInputIoState,10);
				(void)CM_Memcpy(&ioInput[30],10,s_2x2_Ctrl.MineInputIoState,10);
				ret = ENUM_CM_TRUE;
				break;
			default:
				ret = ENUM_CM_FALSE;
				break;
		}
	}
	/*- 返回获取结果 */
	return ret;
}
/**
* @brief 获取两系输入io状态
* @param ioInput 接收缓冲区  取值范围：非空
* @return ENUM_CM_TRUE 成功，ENUM_CM_FALSE 失败
*/
ENUM_CM_RETURN SFM_2x2_GetLastIoInput(OUT CM_UINT8* ioInput,CM_UINT16 size)
{
	/*- 变量初始化 */
	ENUM_CM_RETURN ret = ENUM_CM_FALSE;
	/*- 入参如果为空 */
	if((NULL == ioInput) || (size < 40u))
	{
		/*- 无处理 */
	}
	else
	{
		ret = CM_Memcpy(&ioInput[0],size,s_2x2_InputIoState,40);
	}
	/*- 返回获取结果 */
	return ret;
}
/**
* @brief 时间同步失败清空消息队列
* @param 无
* @return 无
*/
void SFM_2x2_ClearRcvMsgQ(void)
{
	if(CM_FALSE == s_2x2_Ctrl.TimeSyncFlag)
	{
		/*误差过大，清空2x缓冲区*/
		CFM_Net2XFlush();
	}
	else
	{
		/*无处理*/
	}
}

void SFM_2x2_SemPost(void)
{
    if (0x55u == g_PFM_Cfg.M_2x2_Enable)
    {
    	CM_Sem_Post(s_2x2_thread_Ctrl.m_Stop);
    }
    else
    {
    	/* 无处理 */
    }
}

/**
 * 统一置切系标志
 */
static void s_2x2_CloseSwitchFlag(void)
{
	s_2x2_state_Ctrl.LocalSwitchState = ENUM_2x2_SWITCH_CLOSE;
	s_2x2_state_Ctrl.PeerSwitchState = ENUM_2x2_SWITCH_CLOSE;
	s_2x2_state_Ctrl.PartnerSwitchState = ENUM_2x2_SWITCH_CLOSE;
	s_2x2_state_Ctrl.PartPeerSwitchState = ENUM_2x2_SWITCH_CLOSE;
	s_2x2_state_Ctrl.LocalAIDSwitchState = ENUM_2x2_AIDSWITCH_OVER;
	s_2x2_state_Ctrl.PeerAIDSwitchState = ENUM_2x2_AIDSWITCH_OVER;
	s_2x2_state_Ctrl.PartnerAIDSwitchState = ENUM_2x2_AIDSWITCH_OVER;
	s_2x2_state_Ctrl.PartPeerAIDSwitchState = ENUM_2x2_AIDSWITCH_OVER;
	s_2x2_state_Ctrl.ctrSwitchFlag = 0u;
	s_2x2_state_Ctrl.aidSwitchFlag = 0u;
}
/**
 * @brief 输入阶段平台跟随数据的2oo2比较
 */
static void s_2x2_BaseFollow_2oo2Check_Send(void)
{
	CM_UINT32 crc = 0u;
	CM_UINT8 mine_buf[8u] = {0}, peer_buf[8u] = {0};
	CM_INT32 ret = 0;
	/*- 计算本机跟随数据中协议部分的CRC值 */
	crc = CM_Crc32(g_TxBaseFollow, g_TxBaseFollow_len - 12);
	CM_LongToChar(g_TxBaseFollow_len, mine_buf);
	CM_LongToChar(crc, mine_buf + 4u);
	ret = SFM_2oo2_Exchange_Currency(mine_buf, 8u, peer_buf, 8u, ENUM_2oo2_INPUT_EX);
	/*- 计算对机跟随数据的CRC值 */
	CM_RE_ASSERT(ret == 8, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_19, TSCP_DARK_ASSERT_1);
	/*- 比较本机和对机跟随数据的CRC值 */
	if(0 != CM_Memcmp(mine_buf, peer_buf, (CM_SIZE_T)8u))
	{
		MSCP_LOG_DATALEN(g_TxBaseFollow, g_TxBaseFollow_len, "PFM_InputProc g_TxBaseFollow_len");
		CM_RE_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_19, TSCP_DARK_ASSERT_2);
	}
	/*- 比较成功，填入CRC后发送 */
	if(g_TxBaseFollow_len <= (sizeof(g_TxBaseFollow) - 4u))
	{
		(void)CM_Memcpy(g_TxBaseFollow + g_TxBaseFollow_len, sizeof(g_TxBaseFollow) - g_TxBaseFollow_len - 4u, mine_buf + 4, 4u);
		g_TxBaseFollow_len += 4u;
		if(s_2x2_Ctrl.LocalState == ENUM_2x2_MASTER)
		{
			SFM_2x2_Send(g_TxBaseFollow, (CM_UINT32)g_TxBaseFollow_len, ENUM_2x2_MSG_BASE_FOLLOW);
		}
	}

}
/**
 * @brief 周期末阶段，备系接收主系应用跟随CRC后的比较逻辑
 */
static void s_2x2_AppFollow_SyncCheck(void)
{
	CM_UINT32 mine_crc = 0u, partner_crc1 = 0u, partner_crc2 = 0u;
	static CM_UINT32 error_tolerate = 1u;
	mine_crc = CM_LongFromChar(g_TxAppFollow);
	partner_crc1 = CM_LongFromChar(g_RxAppFollowCrc);
	partner_crc2 = CM_LongFromChar(g_RxAppFollowCrc + 4u);

	/* 主系双CPU的CRC不一致 */
	if(partner_crc1 != partner_crc2)
	{
		/* 备系本机与主系其中一个CRC一致 容忍*/
		if(mine_crc == partner_crc1 || mine_crc == partner_crc2)
		{
			if(error_tolerate++ >= 1u)
			{
				MSCP_LOG_MSG("MASTER APPFOLLOW CRC ERROR OVER TOLERATE %d\n", error_tolerate);
				s_2x2_Ctrl.AppFollowCmpFlag = 1u;
			}
			else
			{
				s_2x2_Ctrl.AppFollowCmpFlag = 0u;
				MSCP_LOG_MSG("MASTER APPFOLLOW CRC ERROR TOLERATE %d\n", error_tolerate);
			}
		}
		/* 备系本机与主系都不一致 比较失败宕机*/
		else
		{
			MSCP_LOG_MSG("APPFOLLOW CRC cmp is fail 1\n");
			s_2x2_Ctrl.AppFollowCmpFlag = 1u;
			CM_RE_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_21, TSCP_DARK_ASSERT_1);
		}
	}
	/* 主系双CPU的CRC一致 但与备系本机不一致 比较失败*/
	else if(mine_crc != partner_crc1)
	{
		s_2x2_Ctrl.AppFollowCmpFlag = 1u;
		MSCP_LOG_MSG("APPFOLLOW CRC cmp is fail 2\n");
	}
	/* 主系双CPU的CRC一致 且与备系本机一致 比较成功*/
	else
	{
		MSCP_LOG_MSG("APPFOLLOW CRC cmp is OK\n");
		s_2x2_Ctrl.AppFollowCmpFlag = 0u;
		error_tolerate = 0u;
	}

	if(1u == s_2x2_Ctrl.AppFollowCmpFlag)
	{
		/* 比较失败则设置容忍次数大于0（可能本周期备系校验错误降为离线，但下周期主系失效，导致备系进入容忍分支，认为校验成功又升备） */
		error_tolerate = ((error_tolerate >= 1u) ? error_tolerate : 1u);
		MSCP_LOG_DATALEN(g_TxAppFollow + 8, g_TxAppFollow_len, "PFM_AppFollow_SyncCheck g_TxAppFollow");
	}
}
/**
 * @brief 输出阶段，备系接收主系输出数据CRC后的比较逻辑
 */
static void s_2x2_Output_SyncCheck(IN const CM_UINT8 *CheckBuf, CM_INT32 CheckLen)
{
	CM_UINT32 i = 0u;
	CM_INT32 ret = -1, ret_p1p2 = -1, ret_m1p1 = -1, ret_m1p2 = -1;	/* 记录对系双CRC比较、本机和对系cpu1、本机和对系cpu2比较结果 */
	CM_UINT32 singleCheckLen = CheckLen / 2u;	/* checkbuf记录了两个CPU的校验信息，长度的一半为单个CPU校验数据长度 */
	static CM_UINT32 error_tolerate = 1u;
    /*- 入参检查 */
    CM_ASSERT(NULL != CheckBuf, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_20, TSCP_DARK_ASSERT_1);
	/* 接收的校验数据长度校验 */
	CM_RE_ASSERT(CheckLen == s_2x2_Ctrl.RxCheckLen, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_20, TSCP_DARK_ASSERT_2);
	/* 比较接收的主系校验帧中，主系的两个CPU的CRC，记录结果ret_p1p2 */
	ret_p1p2 = CM_Memcmp((const void*)s_2x2_Ctrl.RxCheckFrame, (const void*)&s_2x2_Ctrl.RxCheckFrame[singleCheckLen], (CM_SIZE_T)singleCheckLen);
	/* 比较备系本机与主系某一个CPU的CRC，记录结果ret_m1p1 */
	ret_m1p1 = CM_Memcmp((const void*)CheckBuf, (const void*)&s_2x2_Ctrl.RxCheckFrame[0], (CM_SIZE_T)singleCheckLen);
	/* 比较备系本机与主系另一个CPU的CRC，记录结果ret_m1p2 */
	ret_m1p2 = CM_Memcmp((const void*)CheckBuf, (const void*)&s_2x2_Ctrl.RxCheckFrame[singleCheckLen], (CM_SIZE_T)singleCheckLen);
	/* 对系（主系）发送的双CPU的CRC不一致 */
	if(0 != ret_p1p2)
	{
		/* 备系本机与主系其中一个CRC一致 容忍*/
		if(0 == ret_m1p1 || 0 == ret_m1p2)
		{
			if(error_tolerate++ >= 1u)
			{
				MSCP_LOG_MSG("MASTER OUTPUT CRC ERROR OVER TOLERATE %d\n", error_tolerate);
				s_2x2_Ctrl.OutPutCheckFailFlag = 1u;
			}
			else
			{
				s_2x2_Ctrl.OutPutCheckFailFlag = 0u;
				s_2x2_Ctrl.LastCheckOKCount = SFM_2x2_GetSysCount();
				MSCP_LOG_MSG("MASTER OUTPUT CRC ERROR TOLERATE %d\n", error_tolerate);
			}
		}
		/* 备系本机与主系都不一致 比较失败*/
		else
		{
			MSCP_LOG_MSG("OUTPUT CRC cmp is fail 1\n");
			s_2x2_Ctrl.OutPutCheckFailFlag = 1u;			
		}
	}
	/* 对系（主系）发送的双CPU的CRC一致，比较失败 */
	else if(0 != ret_m1p1)
	{
		MSCP_LOG_MSG("OUTPUT CRC cmp is fail 2\n");
		s_2x2_Ctrl.OutPutCheckFailFlag = 1u;
		for(i = 0u;i < singleCheckLen;i++)
		{
			if(CheckBuf[i] == s_2x2_Ctrl.RxCheckFrame[i])
			{

			}
			else
			{
				/*- 跳出 */
				break;
			}
		}
		/*记录暗文日志*/
		(void)CFM_DarkLog_Multiple(DARK_LOG_HEX, TSCP_DARK_2X2_OUT_CHECK_FAIL,3u,
									sizeof(CM_UINT8),s_2x2_Ctrl.OutPutCheckFailFlag,
									sizeof(CM_UINT32),i,
									sizeof(CM_UINT32),s_2x2_Ctrl.RxCheckSysCyc);
	}
	/* 主系双CPU的CRC一致 且与备系本机一致 比较成功*/
	else
	{
		MSCP_LOG_MSG("OUTPUT CRC cmp is OK\n");
		/*- 更新输出比较状态 */
		s_2x2_Ctrl.LastCheckOKCount = SFM_2x2_GetSysCount();
		s_2x2_Ctrl.OutPutCheckFailFlag = 0u;
		error_tolerate = 0u;
	}
	/* 备系比较失败宕机*/
	if(1u == s_2x2_Ctrl.OutPutCheckFailFlag)
	{
		/* 比较失败则设置容忍次数大于0（可能本周期备系校验错误降为离线，但下周期主系失效，导致备系进入容忍分支，认为校验成功又升备） */
		error_tolerate = ((error_tolerate >= 1u) ? error_tolerate : 1u);
		/* 打印比较不一致的通道数据 */
        for (i = 1; i <= g_2x2oo2_data_num; i++)
        {
            if ((CM_UINT32)CM_TRUE == g_2x2oo2_tx[g_2x2oo2_base][i].b_2x2_Enable)
            {
                ret = CM_Memcmp(CheckBuf + 4 + (i - 1) * 8, s_2x2_Ctrl.RxCheckFrame + 4 + (i - 1) * 8, 8);
                if(ret != 0)
                {
                    MSCP_LOG_MSG("2x2 output compare err, INDEX = %d, len = %d\n", i, (CM_SIZE_T)g_2x2oo2_tx[g_2x2oo2_base][i].buf_len);
                    MSCP_LOG_BIN(g_2x2oo2_tx[g_2x2oo2_base][i].p_buf, (CM_SIZE_T)g_2x2oo2_tx[g_2x2oo2_base][i].buf_len);
                }
            }
            else
            {
                /*二取标志未使能*/
            }
        }
		if(ENUM_2x2_SLAVE == s_2x2_Ctrl.LocalState)
		{
			CM_RE_ASSERT(0, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_20, TSCP_DARK_ASSERT_3);
		}
	}
}
/**
 * @brief 输入阶段，非主系进行相关CRC校验后跟随
 */
static void s_2x2_BaseFollow_Sync(void)
{
	CM_UINT32 len_prtcl = 0u; /* 协议跟随数据长度 */
    CM_UINT32 len_sfprtcl = 0u; /* 协议跟随数据长度 */
    CM_UINT32 len_pfm = 0u;   /* 平台跟随数据长度 */
	CM_UINT32 calcCrc = 0u, rxCrc = 0u, txCrc = 0u; /* CRC相关变量 */
	CM_UINT32 offset = 0u;	/* 解包用offset*/
	/*- 适配层协议数据跟随*/
	g_RxBaseFollow_len -= 4;/*去除CRC的长度*/
	calcCrc = CM_Crc32(g_RxBaseFollow, (CM_UINT32)g_RxBaseFollow_len - 12u);
	offset = (CM_UINT32)g_RxBaseFollow_len;
	rxCrc = CM_LongFromChar(&g_RxBaseFollow[offset]);
	offset = (CM_UINT32)g_TxBaseFollow_len - 4u;
	txCrc = CM_LongFromChar(&g_TxBaseFollow[offset]);
	if((ENUM_2x2_SLAVE == s_2x2_Ctrl.LocalState) && (txCrc != rxCrc))
	{
		/* 备系自己产生的平台跟随数据与主系不一致，做日志记录 */
		MSCP_LOG_MSG("2x2 BaseFollow CRC Err,TxCrc = %d,RxCrc = %d,Time:%d us\r\n", txCrc,rxCrc,NOW_USED_TIME);
	}
	/*- 比较收到的跟随数据与发送的跟随数据*/
	if(calcCrc == rxCrc)
	{
		offset = 0u;
		len_prtcl = CM_LongFromChar((void*)&g_RxBaseFollow[offset]);
		offset += 4u;
		CM_RE_ASSERT(len_prtcl <= ((CM_UINT32)g_RxBaseFollow_len - 4u), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_22, TSCP_DARK_ASSERT_1);
		SFM_SetPrtclFollowData((void*)&g_RxBaseFollow[offset]);
		offset += len_prtcl;

		/*- sfp协议数据跟随*/
		len_sfprtcl = CM_LongFromChar((void*)&g_RxBaseFollow[offset]);
		offset += 4u;
		CM_RE_ASSERT(len_prtcl + len_sfprtcl <= ((CM_UINT32)g_RxBaseFollow_len - 8u), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_22, TSCP_DARK_ASSERT_2);
		SFM_SetSfpPrtclFollowData(len_sfprtcl, (void*)&g_RxBaseFollow[offset]);
		offset += len_sfprtcl;

		/*- 平台数据跟随*/
		len_pfm = CM_LongFromChar((void*)&g_RxBaseFollow[offset]);
		offset += 4u;
		CM_RE_ASSERT(len_pfm == ((CM_UINT32)g_RxBaseFollow_len - len_prtcl - len_sfprtcl - 12u), SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_22, TSCP_DARK_ASSERT_3);
		CM_RE_ASSERT(len_pfm == 8u, SFM_2x2_MODE, DARK_FAULT_CODE_FUN_ORDER_22, TSCP_DARK_ASSERT_4);
	}
	/*此处使用临时周期号接收,在周期末同步*/
	offset = (CM_UINT32)g_RxBaseFollow_len - 8u;
	s_2x2_Ctrl.SysCycSync = CM_LongFromChar((void*)&g_RxBaseFollow[offset]); /* parasoft-suppress BD-PB-CHECKRET "此处无需检查CM_LongFromChar()的返回值" */
	offset += 4u;
	SFM_SetTxSn(CM_LongFromChar((void*)&g_RxBaseFollow[offset]));
}
