#include "stdarg.h"
#include "DFM_DRV.h"
#include "PFM_CPUUsage.h"
#include "PFM_SelfCheck.h"
#include "PFM_MemoryCheck.h" /* 内存自检 */
#include "PFM_InputOutput.h" /* 内网透传接收 */
#include "PFM_Log.h"
#include "PFM_Cfg.h" /* 版本信息 */
#include "SFM_2x2.h"
#include "SFM_2oo2.h"
#include "SFM_Prtcl.h"
#include "CM_Time.h"
#include "CM_Memory.h"
#include "CFM_Net.h"
#include "PFM_RemoteUpdate.h"
#include "MSCP_APP_API.h"
#ifdef QNX
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif

SERIAL_ID_FUNC p_Serial_Id_Func = NULL;
STATUS_COMMUNICATION_FUNC p_Status_Communication_Func = NULL;
SERIAL_OUT_ATS_VOBC p_Serial_OUT_ATSVOBC_Func = NULL;
SERIAL_IN_VOBC_ATS p_Serial_IN_VOBC_Func = NULL;
pTempAppfunc g_APP_FUNC_SET;
CM_UINT8  *p_gSfpInnetPara;
CM_UINT32 inParamLen;
CM_UINT8* inParam;
CM_UINT8 gCpuUsageParaFlag;
CM_UINT8 gSetTempFlag;
CM_FLOAT32 gMinTemperature;
CM_FLOAT32 gMaxTemperature;
/** 需应用注册的版本号 */
extern STRU_APP_VERSON g_App_Verson;

/**
* @brief 接收应用报文
* @param ch 指定接收通道
* @param pSrcName 源设备ID
* @param pSrcLogicID 源逻辑ID
* @param pLifeTime 报文剩余有效期
* @param rxBuf 收到的应用报文数组
* @param pRxLen 收到的应用报文长度
* @param rxSize 接收应用报文的缓冲区（rxBuf）大小，应不小于可能收到的最长应用报文长度
* @return 函数执行结果
* - 1 成功
* - 0 失败(输入非法)
* @details
* 每次调用获得一条完整的应用报文
* 应用每周期应持续调用本函数直到获得的报文长度 *pRxLen == 0
*/
CM_UINT8 MSCP_AppRecvMsg(IN ENUM_MSCP_MSG_CHN_T ch,
    OUT CM_UINT16 *pSrcName, OUT CM_UINT16 *pSrcLogicID, OUT CM_UINT8 *pLifeTime,
    OUT CM_UINT8 *rxBuf, OUT CM_UINT32 *pRxLen, IN CM_UINT32 rxSize)
{
    /*- 变量初始化 */
    CM_UINT8 rt = 0u;           /* 函数返回值 */

    if ((NULL != pSrcName)
        && (NULL != pSrcLogicID)
        && (NULL != pLifeTime)
        && (NULL != rxBuf)
        && (NULL != pRxLen))
    {
        /*- 输出置零 */
        *pSrcName = 0u;
        *pSrcLogicID = 0u;
        *pLifeTime = 0u;
        /*- 通道类型 */
        switch (ch)
        {
        case ENUM_MSG_OUTNET_SAFE: /*-< 外网安全通信 */
            /*- 从外网安全协议读取应用接收报文 */
            *pRxLen = Prtcl_OutnetSafe_AppRecv(pSrcName, pSrcLogicID, pLifeTime, rxBuf, rxSize);
            /*- 返回 */
            break;
        case ENUM_MSG_INNET_SAFE: /*-< 内网安全通信 */
            *pSrcLogicID = 0u;
            /*- 从内网安全协议读取应用接收报文 */
            *pRxLen = Prtcl_InnetSafe_AppRecv(pSrcName, pLifeTime, rxBuf, rxSize);
            /*- 返回 */
            break;
        case ENUM_MSG_INNET_MAINTENANCE: /*-< 远程部署功能内网安全通信 */
            *pSrcLogicID = 0u;
            /*- 从内网安全协议读取应用接收报文 */
            *pRxLen = Prtcl_InnetSafe_RmRecv(pSrcName, pLifeTime, rxBuf, rxSize);
			MSCP_LOG_BIN(rxBuf,*pRxLen);
            /*- 返回 */
            break;
        case ENUM_MSG_ERROR: /*-< 保留字 */
            /*- 宕机 */
            CM_ASSERT(0, APP_API_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_1);
            /*- 返回 */
            break;
        default:
            /*- 宕机 */
            CM_ASSERT(0, APP_API_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_2);
            /*- 返回 */
            break;
        }
		if(0u < *pRxLen)
		{
			rt = 1u;
		}
		else
		{
			rt = 0u;
		}
    }
    else
	{
		/*- 无处理 */
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_WARNING, 4U, DARK_FAULT_CODE_MERGE(APP_API_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_1));
	}
    /*- 返回 */
    return rt;
}

/**
* @brief 发送应用报文
* @param ch 指定发送通道
* @param dstName 目的设备ID
* @param dstLogicID 目的逻辑ID
* @param txBuf 发送的应用报文数组
* @param txLen 发送的应用报文长度
* @return 函数执行结果
* - 1 成功
* - 0 失败(输入非法)
* @details
* 每次调用发送一条完整的应用报文
* 应用每周期可多次调用本函数从而发送多个应用报文，
* 注意总发送长度不要超过周期通信总量限制
*/
CM_UINT8 MSCP_AppSendMsg(IN ENUM_MSCP_MSG_CHN_T ch, IN CM_UINT16 dstName,
    IN CM_UINT16 dstLogicID, IN const CM_UINT8 *txBuf, IN CM_UINT32 txLen)
{
    /*- 变量初始化 */
    CM_UINT8 rt = 0u;         /* 函数返回值 */

    /*- 入口检查 */
    CM_ASSERT(NULL != txBuf, APP_API_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_1);

    /*- 通道类型 */
    switch (ch)
    {
    case ENUM_MSG_OUTNET_SAFE:/*-< 外网安全通信 */
        /*- 外网安全发送 */
        rt = Prtcl_OutnetSafe_AppSend(dstName, dstLogicID, txBuf, txLen);
        /*- 返回 */
        break;
    case ENUM_MSG_INNET_SAFE: /*-< 内网安全通信 */
        rt = Prtcl_InnetSafe_AppSend(dstName, txBuf, txLen);
        /*- 返回 */
        break;
    case ENUM_MSG_INNET_MAINTENANCE: /*-< 远程部署内网安全通信 */
        rt = Prtcl_InnetSafe_AppRmSend(txBuf, txLen);
        MSCP_LOG_MSG("MSCP_AppSendMsg txLen = %d \n",txLen);
        MSCP_LOG_BIN(txBuf,txLen);
        /*- 返回 */
        break;
    case ENUM_MSG_ERROR: /*- 保留字 */
        /*- 宕机 */
        CM_ASSERT(0, APP_API_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_2);
        /*- 返回 */
        break;
    default:
        /*- 宕机 */
        CM_ASSERT(0, APP_API_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_3);
        /*- 返回 */
        break;
    }
    /*- 返回 */
    return rt;
}

/**
* @brief 断开指定的外网安全通信链接
* @param devID 设备ID
* @param logicID 逻辑ID
* @return 执行结果
* - 1 成功
* - 0 失败
*/
CM_UINT8 MSCP_Outnet_Disconnect(CM_UINT16 devID, CM_UINT16 logicID)
{
    return SFM_OutnetDisconnect(devID, logicID);
}

/**
* @brief 接收外网透传报文
* @param rxBuf 收到的应用报文数组
* @param rxSize 接收应用报文的缓冲区（rxBuf）大小，应不小于可能收到的最长应用报文长度
* @return 收到的应用报文长度
* @details
* 每次调用获得一条完整的应用报文
* 每周期应持续调用本函数直到获得的报文长度 *pRxLen == 0
*/
CM_UINT32 MSCP_OutnetRaw_AppRecv(OUT CM_UINT8* rxBuf, IN CM_UINT32 rxSize)
{
    return PFM_OutnetRaw_AppRecv(rxBuf, rxSize);
}

/**
* @brief 发送外网透传报文
* @param txBuf 发送的应用报文数组
* @param txLen 发送的应用报文长度
* @param dstName 目的设备ID
* @param dstLogicID 目的逻辑ID
* @param type 类型
* @return 函数执行结果
* - 1 成功
* - 0 失败(输入非法)
* @details
* 每次调用发送一条完整的应用报文
* 每周期可多次调用本函数从而发送多个应用报文，
* 注意总发送长度不要超过周期通信总量限制
*/
CM_UINT8 MSCP_OutnetRaw_AppSend(IN const CM_UINT8* txBuf, IN CM_UINT32 txLen, IN CM_UINT16 dstName, IN CM_UINT16 dstLogicID, CM_UINT16 type)
{
    return PFM_OutnetRaw_AppSend(txBuf, txLen, dstName, dstLogicID, type);
}
/**
* @brief 接收内网透传报文
* @param ch 通道ID
* @param pSrcName 源设备ID
* @param rxBuf 收到的应用报文数组
* @param rxSize 接收应用报文的缓冲区（rxBuf）大小，应不小于可能收到的最长应用报文长度
* @return 收到的应用报文长度
* @details
* 每次调用获得一条完整的应用报文
* 每周期应持续调用本函数直到获得的报文长度 *pRxLen == 0
*/
CM_UINT32 MSCP_InnetRaw_AppRecv(IN CM_INT32 ch, OUT CM_UINT16* pSrcName, OUT CM_UINT8* rxBuf, IN CM_UINT32 rxSize)
{
    return PFM_InnetRaw_AppRecv(ch, pSrcName, rxBuf, rxSize);
}
/**
* @brief 快速接收内网透传报文
* @param ch 通道ID
* @param pSrcName 源设备ID
* @param rxBuf 收到的应用报文数组二级指针
* @return 收到的应用报文长度
* @details
* 每次调用获得一条完整的应用报文
* 每周期应持续调用本函数直到获得的报文长度 *pRxLen == 0
*/
CM_UINT32 MSCP_InnetRaw_AppRecv_Fast(IN CM_INT32 ch, OUT CM_UINT16* pSrcName, const OUT CM_UINT8** rxBuf)
{
    return PFM_InnetRaw_AppRecv_Fast(ch, pSrcName, rxBuf);
}

/**
* @brief 接收内网透传辅助信息
* @param ch 通道ID
* @param MainInfoBuf 本机辅助信息数组指针
* @param PeerInfoBuf 邻机辅助信息数组指针
* @param rxSize		  接收缓冲区长度
* @param PeerInfoLen 邻机辅助信息报文长度
* @return 收到的本机辅助信息报文长度
* @details
* 每周期调用一次，可获得全部辅助信息，再根据对应长度（8字节或12字节）解析时间戳或序列号
*/
CM_UINT32 MSCP_InnetRawHelpInfo_AppRecv(IN CM_INT32 ch, OUT CM_UINT8* MainInfoBuf,OUT CM_UINT8* PeerInfoBuf,IN CM_INT16 rxSize,OUT CM_UINT16 *PeerInfoLen)
{
	return PFM_InnetRawHelpInfo_AppRecv(ch,MainInfoBuf,PeerInfoBuf,rxSize,PeerInfoLen);
}

/**
* @brief 发送内网透传报文
* @param ch 通道ID
* @param dstName 目的设备ID
* @param txBuf 发送的应用报文数组
* @param txLen 发送的应用报文长度
* @return 函数执行结果
* - 1 成功
* - 0 失败(输入非法)
* @details
* 每次调用发送一条完整的应用报文
* 每周期可多次调用本函数从而发送多个应用报文，
* 注意总发送长度不要超过周期通信总量限制
*/
CM_UINT8 MSCP_InnetRaw_AppSend(IN CM_INT32 ch, IN CM_UINT16 dstName, IN const CM_UINT8* txBuf, IN CM_UINT32 txLen)
{
    return PFM_InnetRaw_AppSend(ch, dstName, txBuf, txLen);
}

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

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

/**
* @brief 设置跟随数据
* @param[in] Data[] 跟随数据数组
* @param[in] Len 跟随数据长度
* @return 函数执行结果
* - 1 成功
* - 0 失败(输入非法)
* @note
* 无论本系是否为主，应用都应当每周期设置一次跟随数据；
* 本系非主时平台不会发送该数据，但会用于双系一致性的校验。
* 跟随数据量最大为1024*1000字节。
* @see :: APP_API_FollowUp
*/
CM_UINT8 MSCP_SetFollowData(IN const CM_UINT8 Data[], IN CM_UINT32 Len)
{
	return SFM_2x2_SetFollowData(Data, Len);
}

/**
* @brief 获取系统周期号
* @return 当前的系统周期号
* @note
* 一个固定周期自增的周期号；
* 对于2x2系统，2x2双系的周期号会被自动同步到与主系一致。
*/
CM_UINT32 MSCP_GetSysCount(void)
{
	return SFM_2x2_GetSysCount();
}

/**
* @brief 获取本机外网ID
* @return 本机外网ID
* @note 1字节类型+1字节ID，大端格式，来自INI配置文件。
*/
CM_UINT16 MSCP_GetOutnetID(void)
{
	return PFM_CFG_GetOutnetID();
}

/**
* @brief 获取本机内网ID
* @return 本机内网ID
* @note 1字节类型+1字节ID，大端格式，来自INI配置文件。
*/
CM_UINT16 MSCP_GetInnetID(void)
{
	return PFM_CFG_GetInnetID();
}

/**
* @brief 获取板卡ID
* @return 本机的板卡ID
* @note 板卡ID的宏定义参见本文件头部
*/
CM_UINT8 MSCP_GetBoardID(void)
{
	return PFM_CFG_GetBoardID();
}

/**
* @brief 获取CPUID
* @return CPUID
* @details
* CPUID根据配置文件确定
*/
CM_UINT8 MSCP_GetCpuID(void)
{
	return PFM_CFG_GetCpuID();
}

/**
* @brief 获取平台软件版本号和MD5码
* @param[out] version 软件版本号 v[0].v[1].v[2].v[3]
*/
void MSCP_GetBaseWareVer(OUT CM_UINT8 version[4])
{
    /*- 输出平台软件版本 */
    version[0] = MSCP_SW_VERION[0];
    version[1] = MSCP_SW_VERION[1];
    version[2] = MSCP_SW_VERION[2];
    version[3] = MSCP_SW_VERION[3];
}

/**
* @brief 获取精确上电时间
* @return 系统上电至调用时刻的ns数
* @details 从系统上电开始计时，不受时钟同步等操作的影响。
*/
CM_UINT64 MSCP_GetTick(void)
{
    /*- 返回精确时间 */
    return CM_GetTick();
}
/**
* @brief 获取UTC基准时间
* @return 初始化记录UTC时间的us数
* @details 从周期开始初始化固定值，不受时钟同步等操作的影响。
*/
CM_UINT64 MSCP_GetUTCTick(void)
{
    /*- 返回精确时间 */
    return DFM_GetUTCBaseTick();
}
/**
* @brief 重写pSerial函数指针(串口扩展版使用),二次开发手册限制初始化时设置。
*/
void MSCP_SetSerial(SERIAL_ID_FUNC p)
{
	p_Serial_Id_Func = p;
}

/**
* @brief 重写设备id和红蓝网通信情况。
* @param p 注册的函数指针 取值范围(如果无需获取可以为NULL,如果获取则非空)
*/
void MSCP_SetSrcId(STATUS_COMMUNICATION_FUNC p)
{
	p_Status_Communication_Func = p;
}

/**
* @brief 变量内存自检注册初始化
* @param pMemAddr注册变量的首地址
* 		 dataLen 注册变量的大小
*/
void MSCP_MemCheck_Register(CM_UINT8 *pMemAddr,CM_UINT32 dataLen)
{
	PFM_MemCheck_Register(pMemAddr,dataLen);
}

/**
* @brief 初始化协议参数
* @param inParamLen 长度
* 		 inParam 指针
*/
void MSCP_ParamData(CM_UINT8* pParam,CM_UINT32 ParamLen)
{
	inParamLen = ParamLen;
	inParam = pParam;
}

/**
* @brief 应用记录格式化字符串日志
* @param filename 文件路径
* @param func 函数名
* @param line 行号
* @param fmt 格式化字符串
*/
void MSCP_APP_LOG_MSG(IN const CM_CHAR *filename, IN const CM_CHAR *func, IN CM_INT32 line, IN const CM_CHAR* fmt, ...)
{
    /*- 变量初始化 */
    va_list argList;
    CM_CHAR msgBuf[4096+256];
    CM_INT32 headLen = 0;
    CM_INT32 msgLen = 0;
    /*- 记录文件名、函数名、行号 */
    headLen = snprintf(msgBuf, sizeof(msgBuf), "as:");
    va_start(argList, (fmt));
    /*- 记录日志内容 */
    msgLen += vsnprintf(msgBuf + headLen, sizeof(msgBuf) - (CM_SIZE_T)headLen, fmt, argList);
    va_end(argList);

#ifdef WIN32
    printf("%s", msgBuf + headLen);
#endif

    (void)CFM_AppLog_Send((CM_UINT8*)msgBuf, headLen + msgLen);
    /*CFM_AppStrLog_Send((CM_UINT8*)msgBuf, msgLen);*/
}

/**
* @brief 应用记录二进制日志
* @param filename 文件路径
* @param func 函数名
* @param line 行号
* @param Buf 二进制数组指针
* @param Len 二进制数组长度
*/
void MSCP_APP_LOG_BIN(IN const CM_CHAR *filename, IN const CM_CHAR *func, IN CM_INT32 line, IN const CM_UINT8 *Buf, IN CM_UINT32 Len)
{

    /*- 变量初始化 */
    CM_UINT32 i = 0u;
    CM_UINT32 cut = (Len/CFM_INNET_LOG_BIN_SIZE) + (((Len%CFM_INNET_LOG_BIN_SIZE) > 0U)?(1u):(0u));
    CM_CHAR tmepBuf[CFM_INNET_LOG_SIZE];
    CM_UINT32 msgLen = 0u;
    for(i = 0u;i < cut;i++)
    {
    	(void)snprintf(tmepBuf, sizeof(tmepBuf), "ab:");
    	msgLen = (((cut-i)>1u)?CFM_INNET_LOG_BIN_SIZE:(Len%CFM_INNET_LOG_BIN_SIZE));
    	(void)CM_Memcpy(&tmepBuf[3],CFM_INNET_LOG_BIN_SIZE,&Buf[i*CFM_INNET_LOG_BIN_SIZE],(CM_SIZE_T)msgLen);
    	/*- 输出日志信息 */
    	(void)CFM_BaseLog_Send((CM_UINT8*)tmepBuf, msgLen+3u);
    }
}

/**
* @brief 设置内网协议p_gSfpInnetPara
* @param p_gSfpInnetPara 指针
*/
void MSCP_SetSfpInnetPara(CM_UINT8* pSfpInnetData)
{
	p_gSfpInnetPara = pSfpInnetData;
}

/**
* @brief 初始化应用函数入口
*/
void MSCP_SetAppFunc(pSetAppfunc pApp1, pSetAppfunc pApp2, pSetAppfunc pApp3, pSetAppfunc pApp4, pSetAppfunc pApp5)
{
	g_APP_FUNC_SET.pApp1 = pApp1;
	g_APP_FUNC_SET.pApp2 = pApp2;
	g_APP_FUNC_SET.pApp3 = pApp3;
	g_APP_FUNC_SET.pApp4 = pApp4;
	g_APP_FUNC_SET.pApp5 = pApp5;
}

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

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

/**
* @brief 获取板卡温度
* @return 返回板卡温度
*/
CM_FLOAT64 MSCP_GetTemperature(void)
{
	return DFM_Get_Tmp112();
}

/**
* @brief 设置板卡温度范围
* @param MinTemperature 最低温度
* @param MaxTemperature 最高温度
* @return 函数执行结果
* - 1 成功
* - 0 失败
*/
CM_UINT8 MSCP_SetTemperature(CM_FLOAT32 MinTemperature , CM_FLOAT32 MaxTemperature)
{
	return PFM_SetTemperature(MinTemperature,MaxTemperature);
}

/**
* @brief 内网透传解析功能-注册函数
* @param RAW_ALGORITHM *p_Fun 注册函数
* @return 无
* @details 注册数组，需要注册8个函数，如果不需要解析请注册NULL。
* @details 此函数应尽快执行完毕（耗时可能会引起丢包），并且不允许加打印。
*/
void MSCP_InnetRaw_analysisFun(RAW_ALGORITHM *p_Fun)
{
	CM_UINT8 i = 0U;
    CM_INT32 RawNum = g_PFM_Cfg.Local_Cfg.Port_Innet_Raw_Num + g_PFM_Cfg.Local_Cfg.Port_Innet_Raw_Extend_Num;
    for(i = 1u;i <= (CM_UINT8)RawNum;i++)
	{
		p_ALGORITHM_Fun[i] = p_Fun[i-1U];
	}
}
/**
* @brief 获取本机通用IP地址
* @param 无
* @return IP地址
* @details 此函数仅允许在初始化阶段使用
*/
CM_UINT32 MSCP_GetLocal_ComIp(void)
{
	return (CM_UINT32)inet_addr(g_PFM_Cfg.Local_Cfg.IP_Com);
}
/**
* @brief 获取本机通用扩展IP地址
* @param 无
* @return IP地址
* @details 此函数仅允许在初始化阶段使用
*/
CM_UINT32 MSCP_GetLocal_ComExtendIp(void)
{
	return (CM_UINT32)inet_addr(g_PFM_Cfg.Local_Cfg.IP_Com_Extend);
}
/**
* @brief 应用2取交换
* @param pMyData 本机数据指针 取值范围：非空
* @param DataLen 本剧数据长度 取值范围：0~0x7FFFFFFF
* @param pPeerData 邻机数据指针 取值范围：非空
* @param DataSize 邻机数据缓冲区大小 取值范围：0~0xFFFFFFFF
* @return 收到的邻机数据长度 取值范围：0~0x7FFFFFFF
* @details 入参变量均由调用函数检测是否合法,此函数作用只为接口
*/
CM_INT32 MSCP_APP_2oo2(IN const CM_UINT8 * pMyData, IN CM_INT32 DataLen, OUT CM_UINT8 * pPeerData, IN CM_UINT32 DataSize)
{
	/*- 执行2取应用交换并且返回结果 */
	return (0x55u == g_PFM_Cfg.M_2oo2_Enable) ? SFM_2oo2_Currency_App(pMyData, DataLen, pPeerData, DataSize) : 0;
}

/**
* @brief 获取板卡运行状态
* @return 板卡运行状态
* - ENUM_BOARDSTATE_ERROR = 0,   未知状态
* - ENUM_BOARDSTATE_RUN = 1,     运行状态
* - ENUM_BOARDSTATE_EXIT = 2,    退出运营状态
* - ENUM_BOARDSTATE_UPDATE = 3,  故障可更新文件状态
* - ENUM_BOARDSTATE_DEFAULT = 4, 故障不可更新文件状态
*/
ENUM_BOARD_STATE_T MSCP_GetBoardState(void)
{
	return PFM_GetBoardState();
}

/**
* @brief 设置板卡运行状态
* @param state 板卡运行状态
* - ENUM_BOARDSTATE_ERROR = 0,   未知状态
* - ENUM_BOARDSTATE_RUN = 1,     运行状态
* - ENUM_BOARDSTATE_EXIT = 2,    退出运营状态
* - ENUM_BOARDSTATE_UPDATE = 3,  故障可更新文件状态
* - ENUM_BOARDSTATE_DEFAULT = 4, 故障不可更新文件状态
*/
void MSCP_SetBoardState(ENUM_BOARD_STATE_T state)
{
	PFM_SetBoardState_APP(state);
}


/**
* @brief 应用将应用版本号写入平台
* @param APP_VERSION 版本号 取值范围:非空
*/
void MSCP_SetAppVersion(IN CM_UINT8 APP_VERSION[])
{
	/*- 入参不为空 */
	if(NULL != APP_VERSION)
	{
		/*- @alias 应用将应用版本号写入平台 */
		if(g_App_Verson.registerVerson[0].flag == 0u)
		{
			g_App_Verson.registerVerson[0].flag = 1u;
			g_App_Verson.versonNumber++;
		}
		else
		{
			/*- 无处理 */
		}
		g_App_Verson.registerVerson[0].verson[0] = APP_VERSION[0];
		g_App_Verson.registerVerson[0].verson[1] = APP_VERSION[1];
		g_App_Verson.registerVerson[0].verson[2] = APP_VERSION[2];
		g_App_Verson.registerVerson[0].verson[3] = APP_VERSION[3];
	}
	else
	{
		/*- 无处理 */
		MSCP_LOG_MSG("MSCP_SetAppVersion is NULL\n");
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_WARNING, 4U, DARK_FAULT_CODE_MERGE(APP_API_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_1));
	}

}

/**
* @brief 应用将FS版本号写入平台
* @param FS_VERSION FS数据版本号 取值范围:非空
*/
void MSCP_SetFsVersion(IN CM_UINT8 FS_VERSION[])
{
	/*- 入参不为空 */
	if(NULL != FS_VERSION)
	{
		/*- @alias 应用将FS版本号写入平台 */
		if(g_App_Verson.registerVerson[1].flag == 0u)
		{
			g_App_Verson.registerVerson[1].flag = 1u;
			g_App_Verson.versonNumber++;
		}
		else
		{
			/*- 无处理 */
		}
		g_App_Verson.registerVerson[1].verson[0] = FS_VERSION[0];
		g_App_Verson.registerVerson[1].verson[1] = FS_VERSION[1];
		g_App_Verson.registerVerson[1].verson[2] = FS_VERSION[2];
		g_App_Verson.registerVerson[1].verson[3] = FS_VERSION[3];
	}
	else
	{
		/*- 无处理 */
		MSCP_LOG_MSG("MSCP_SetFsVersion is NULL\n");
		(void)CFM_DarkLog_Storage(DARK_LOG_HEX, TSCP_DARK_WARNING, 4U, DARK_FAULT_CODE_MERGE(APP_API_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_1));
	}

}

/**
* @brief 应用将Scade版本号写入平台
* @param SCADE_VERSION Scade数据版本号 取值范围:非空
*/
void MSCP_SetScadeVersion(IN CM_UINT8 SCADE_VERSION[])
{
	/*- 入参不为空 */
	if(NULL != SCADE_VERSION)
	{
		/*- @alias 应用将Scade版本号写入平台 */
		if(g_App_Verson.registerVerson[2].flag == 0u)
		{
			g_App_Verson.registerVerson[2].flag = 1u;
			g_App_Verson.versonNumber++;
		}
		else
		{
			/*- 无处理 */
		}
		g_App_Verson.registerVerson[2].verson[0] = SCADE_VERSION[0];
		g_App_Verson.registerVerson[2].verson[1] = SCADE_VERSION[1];
		g_App_Verson.registerVerson[2].verson[2] = SCADE_VERSION[2];
		g_App_Verson.registerVerson[2].verson[3] = SCADE_VERSION[3];
	}
	else
	{
		/*- 无处理 */
		MSCP_LOG_MSG("MSCP_SetScadeVersion is NULL\n");
	}


}

/**
* @brief 获取平台暂存的红蓝网设备信息
* @param RedBuf 红网缓冲区 取值范围:非空
* @param BlueBuf 篮网缓冲区 取值范围：非空
* @details RCI用于获取平台暂存的红蓝网设备信息,长度大于等于16*18
*/
void MSCP_GetRciTempBuf(OUT CM_UINT16* RedBuf, OUT CM_UINT16* BlueBuf)
{
	PFM_GetRciTempBuf(RedBuf,BlueBuf);
}

/**
* @brief 获得是否为在因为切系后,主系降为离线的3周期内的标志。
* @return 是否为切系后的5周期
* - 0 不在切系后的5周期内
* - 1 在切系后的5周期内
* @details 此切系状态用于应用获取到离线时判断原因
*/
CM_UINT8 MSCP_2x2_GetSwitchFlag(void)
{
	/*- 获取是否切系标志位 */
	return 0;//SFM_2x2_GetSwitchFlag();
}

/**
* @brief 应用配置ip、端口、使能等可配置变量
* @param app_data 应用配置结构体 取值范围:非空
* @details 此配置用来代替main_base.ini
*/
void MSCP_Set_APP_ConfigData(STRU_APP_CFG_T *app_data)
{
	/*- 应用配置ip、端口、使能等可配置变量 */
	PFM_Set_APP_ConfigData(app_data);
}

/**
* @brief 查询链路状态
* @param destType 对方设备类型 取值范围：0~0xff
* @param destId 对方设备ID 取值范围：0~0xff
* @param logId 逻辑id(若卡斯柯的CI与VOBC通信，需要填写VOBC的站台号。其他的系统填0。) 取值范围：0~0xff
* @return 安全通道链路状态
* 	  0：不存在该条链路，返回错误
*     0x17：链路在数据传输正常状态
*     0x2b：链路在通信中断状态
*     0x33：链路在准备建立链接状态
*     0x4e：链路在等待建立链接状态
*     0x01: 表示刷新无用的链路
*/
CM_UINT8 MSCP_GetLnkStatus(CM_UINT8 destType,CM_UINT8 destId,CM_UINT16 logId)
{
	/*- 获取安全通道链路状态 */
	return SFM_GetLnkStatus(destType, destId, logId);
}

/**
* @brief 重写输出ats转车数据备用通道判断函数(串口扩展版)。
* @param p 注册的函数指针 取值范围(如果无需获取可以为NULL,如果获取则非空)
* @details 此函数指针为一个返回值,三个参数。
* 		      返回值ENUM_CM_RETURN 0x55或0xaa
* 		      参数1入参CM_UINT16
* 		      参数2出参CM_UINT16*
* 		      参数3出参CM_UINT16*
*/
void MSCP_SetOutAtsVobcFunc(SERIAL_OUT_ATS_VOBC p)
{
	/*- 重写输出ats转车数据备用通道判断函数 */
	p_Serial_OUT_ATSVOBC_Func = p;
}

/**
* @brief 重写输入ats转车数据备用通道判断函数(串口扩展版)。
* @param p 注册的函数指针 取值范围(如果无需获取可以为NULL,如果获取则非空)
* @details 此函数指针为一个返回值,三个参数。
* 		      返回值ENUM_CM_RETURN 0x55或0xaa
* 		      参数1入参CM_UINT16
*/
void MSCP_SetInVobcAtsFunc(SERIAL_IN_VOBC_ATS p)
{
	/*- 重写输入ats转车数据备用通道判断函数 */
	p_Serial_IN_VOBC_Func = p;
}

/**
* @brief 读取插箱板卡id(此id为交换机版的拨码)
* @return 返回插箱板卡id 取值范围：0~0xFF
* @details 其中高4位bits为插箱id 低四位bits为板卡id
*/
CM_UINT8 MSCP_GetDrvBoardID(void)
{
	/*- 获取插箱板卡id */
	return DFM_getBoardID();
}
/**
* @brief 接收外网心跳报文（自检信息）
* @param rxBuf 收到的应用报文数组
* @param rxSize 接收应用报文的缓冲区（rxBuf）大小，应不小于可能收到的最长应用报文长度
* @return 收到的应用报文长度
* @details
* 每次调用获得一条完整的应用报文
* 每周期应持续调用本函数直到获得的报文长度 *pRxLen == 0
*/
CM_UINT32 MSCP_OutNetHeart_AppRecv(OUT CM_UINT8* rxBuf, IN CM_UINT32 rxSize)
{
    return PFM_OutnetHeart_AppRecv(rxBuf, rxSize);
}

/**
* @brief 获取两系输入io状态
* @param ioInput 接收缓冲区  取值范围：非空
* @param size 缓冲区大小  取值范围：大于40字节
* @return ENUM_CM_TRUE 成功，ENUM_CM_FALSE 失败
* @details 入参变量均由下层函数检测是否合法,此函数作用只为接口
* 数据内容为：A1(10字节)+A2(10字节)+B1(10字节)+B2(10字节)
*/
ENUM_CM_RETURN MSCP_2x2_GetLastIoInput(OUT CM_UINT8* ioInput,CM_UINT16 size)
{
	/*- 获取两系输入io状态并返回结果 */
	return SFM_2x2_GetLastIoInput(ioInput,size);
}

/**
* @brief 设置捕获信号(初始化调用)
*/
void MSCP_SetSignal(CM_INT32 SIGNAL)
{
	PFM_SetSignal(SIGNAL);
}

/**
* @brief 设置应用运行步骤(周期中调用)
*/
void MSCP_SetAppCheck(CM_INT32 appCheck)
{
	PFM_SetAppCheck(appCheck);
}
