/**
 * @file CFM_Sync.c
 * @brief 时间和信息同步功能实现文件
 * 
 * 该文件包含了系统所需的时间同步和信息同步相关函数，
 * 负责维护系统内各模块间的时间一致性以及数据信息的同步处理。
 * 
 * 主要功能包括：
 * - 系统时间同步机制
 * - 模块间信息同步处理
 * - 同步状态监控与维护
 * 
 * @author [硬件平台部平台软件组]
 * @date [2025-12-01]
 * @version [1.0]
 */


#include "CFM_Sync.h"
#include "CFM_Net.h"
#include "PFM_Log.h"
#include "SFM_2oo2.h"
#include "CM_MultiThread.h"
#include "CM_Memory.h"
#include "CM_Atomic.h"
#include "CM_UDP.h"
#include "DFM_Time.h"
#include "CM_Convert.h"
#include "SFM_2x2.h"



#define TIME_SYNC_2oo2  (0) //2oo2时间同步结构体下标
#define TIME_SYNC_2x    (1) //2x时间同步结构体下标
#define TIME_OFFSET_LOCAL (0) //本地时间偏移量
#define TIME_OFFSET_PEER  (1) //对端时间偏移量
static STRU_CFM_TIME_CTRL_T s_TimeCtrl[10] = {0};
#define SFM_2oo2_TM_FIX_VAL_NS       (3 * CM_MILLION)     /* 2oo2校时门限，单位:ns */
#define SFM_2x2_TM_FIX_VAL_NS        (10 * CM_MILLION)    /* 2x最小调整偏差，单位:ns */
#define SFM_TIME_SYNC_TOLERANCE_COUNT (5u)                /* 时间同步切换， 丢失容忍次数*/

static CM_THREAD_FUNC_T t_Sync_TimeThread(IN CM_Thread_Arg_Struct_T* arg);
/**
 * @brief 计算平均偏移量（去除极值后）
 *
 * 维护一个大小为10的环形数组，当数组满时进行排序并去除极值后计算平均值
 *
 * @param offset 当前时间偏移量
 * @param circular_buf 环形数组结构体指针
 * @return 计算出的平均值，如果数组未满则返回当前offset
 */
static CM_INT64 calculate_average_offset(CM_INT64 offset, STRU_CIRCULAR_BUFFER_T *circular_buf);

/**
 * @brief 清空环形缓冲区
 * 
 * 将环形缓冲区的计数器和索引重置为0，并将缓冲区内的所有数据清零，
 * 实现环形缓冲区的一键清空功能。
 * 
 * @param[in,out] circular_buf 环形缓冲区结构体指针
 * 
 * @note 该函数会:
 *       - 将缓冲区数据计数器(count)重置为0
 *       - 将写入索引(index)重置为0
 *       - 将缓冲区内的所有数据清零
 * 
 * @see STRU_CIRCULAR_BUFFER_T
 */
static void CFM_ClearCircularBuf(STRU_CIRCULAR_BUFFER_T *p_circular);
static ENUM_CM_RETURN CircularBuf_Init(STRU_CIRCULAR_BUFFER_T *p_circular);
static CM_INT64 CFM_Get_2x_offset(CM_INT64 local_offse, CM_INT64 peer_offset);
static CM_INT64 CFM_Get_2oo2_offset(CM_INT64 local_offset, CM_INT64 peer_offset);

/**
 * @brief 获取时间同步配置信息
 * 
 * 从全局配置结构体中提取时间同步相关配置信息，包括本机和对端的IP地址
 * 及端口号，填充到时间同步地址结构体中。
 * 
 * @param[out] pCfg 时间同步地址配置结构体指针
 * 
 * @note 该函数会填充以下配置信息：
 *       - 本机2oo2时间同步地址和端口
 *       - 对端2oo2时间同步地址和端口
 *       - 本机2x时间同步地址和端口
 *       - 对端2x时间同步地址和端口
 *       - 对端区域A时间同步地址和端口
 *       - 对端区域B时间同步地址和端口
 * 
 * @see STRU_CFM_TIME_ADDR_T
 * @see g_PFM_Cfg
 */
void CFM_Get_Cfg(OUT STRU_CFM_TIME_ADDR_T *pCfg)
{
    if(NULL != pCfg)
    {
        (void)CM_Memcpy(pCfg->Local_2oo2_Addr.IP, sizeof(pCfg->Local_2oo2_Addr.IP), g_PFM_Cfg.Local_Cfg.IP_2oo2, sizeof(g_PFM_Cfg.Local_Cfg.IP_2oo2));//获取本机2oo2IP地址
        pCfg->Local_2oo2_Addr.Port = g_PFM_Cfg.Local_Cfg.Port_2oo2_Sync_Time;//获取本机2oo2校时端口号

        (void)CM_Memcpy(pCfg->Peer_2oo2_Addr.IP, sizeof(pCfg->Peer_2oo2_Addr.IP), g_PFM_Cfg.Peer_Cfg.IP_2oo2, sizeof(g_PFM_Cfg.Peer_Cfg.IP_2oo2));//获取对端2oo2IP地址
        pCfg->Peer_2oo2_Addr.Port = g_PFM_Cfg.Peer_Cfg.Port_2oo2_Sync_Time;//获取对端2oo2校时端口号

        (void)CM_Memcpy(pCfg->Local_4x_Addr.IP, sizeof(pCfg->Local_4x_Addr.IP), g_PFM_Cfg.Local_Cfg.IP_4x2, sizeof(g_PFM_Cfg.Local_Cfg.IP_4x2));//获取本机2xIP地址
        pCfg->Local_4x_Addr.Port = g_PFM_Cfg.Local_Cfg.Port_4x2_Sync_Time;//获取本机2x校时端口号

        (void)CM_Memcpy(pCfg->Partner_Addr.IP, sizeof(pCfg->Partner_Addr.IP), g_PFM_Cfg.Partner_Cfg.IP_4x2, sizeof(g_PFM_Cfg.Partner_Cfg.IP_4x2));//获取对端2xIP地址
        pCfg->Partner_Addr.Port = g_PFM_Cfg.Partner_Cfg.Port_4x2_Sync_Time;//获取对端2x校时端口号

        (void)CM_Memcpy(pCfg->Partner_Area_Addr_A.IP, sizeof(pCfg->Partner_Area_Addr_A.IP), g_PFM_Cfg.Partner_Area_A_Cfg.IP_4x2, sizeof(g_PFM_Cfg.Partner_Area_A_Cfg.IP_4x2));//获取对端2xIP地址
        pCfg->Partner_Area_Addr_A.Port = g_PFM_Cfg.Partner_Area_A_Cfg.Port_4x2_Sync_Time;//获取对端2x校时端口号

        (void)CM_Memcpy(pCfg->Partner_Area_Addr_B.IP, sizeof(pCfg->Partner_Area_Addr_B.IP), g_PFM_Cfg.Partner_Area_B_Cfg.IP_4x2, sizeof(g_PFM_Cfg.Partner_Area_B_Cfg.IP_4x2));//获取对端2xIP地址
        pCfg->Partner_Area_Addr_B.Port = g_PFM_Cfg.Partner_Area_B_Cfg.Port_4x2_Sync_Time;//获取对端2x校时端口号


    }
    else
    {
        CM_NM_ASSERT(0, 0,0,0);
    }
}

/**
 * @brief 初始化时间同步功能
 * 
 * 创建UDP套接字、互斥锁，并启动时间同步线程，完成时间同步模块的初始化工作。
 * 
 * @param[in] TimeType 时间同步类型（ENUM_TIME_2oo2或ENUM_TIME_2x）
 * @param[in] IP 本地IP地址字符串
 * @param[in] Port 本地端口号
 * @param[in] DevNum 目标设备数量
 * @param[in] DevAddr 目标设备地址数组指针
 * @param[in,out] TimeCtrl 时间同步控制结构体指针
 * 
 * @return ENUM_CM_RETURN
 * @retval ENUM_CM_TRUE  初始化成功
 * @retval ENUM_CM_FALSE 初始化失败
 * 
 * @note 该函数会创建一个时间同步线程，负责处理时间同步协议流程
 * @see t_Sync_TimeThread
 */
ENUM_CM_RETURN CFM_TimeSync_Init(IN CM_UINT8 DevNum)
{ 
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;
    CM_BOOL rtThread = CM_FALSE;
    CM_UINT8 i = 0;
    CM_CHAR threadName[32] = {0};  // 用于存储线程名称

    for(i = 0; i < DevNum; i++)
    {
        /* 读取配置相关配置 */
        CFM_Get_Cfg(&s_TimeCtrl[i].time_addr);

        /*互斥锁初始化*/
        rt = CM_Mutex_Init(&s_TimeCtrl[i].mutex);
        CM_NM_ASSERT(ENUM_CM_TRUE == rt, 0,0,0);


        if(TIME_SYNC_2oo2 == i)
        {
            
            /*二取时间初始化*/
            s_TimeCtrl[i].circular_buf.size = CIRCULAR_BUFFER_SIZE;
            s_TimeCtrl[i].destDev_Num = 1;
            s_TimeCtrl[i].time_type = TIME_SYNC_2oo2;
            (void)CM_Memcpy(s_TimeCtrl[i].local_addr.IP , sizeof(s_TimeCtrl[i].local_addr.IP), s_TimeCtrl[i].time_addr.Local_2oo2_Addr.IP, sizeof(s_TimeCtrl[i].time_addr.Local_2oo2_Addr.IP));
            s_TimeCtrl[i].local_addr.Port = s_TimeCtrl[i].time_addr.Local_2oo2_Addr.Port; /*本地设备地址*/
            s_TimeCtrl[i].destDev_addr[0] = s_TimeCtrl[i].time_addr.Peer_2oo2_Addr; /*目标设备地址*/
            
        }
        else if(TIME_SYNC_2x == i)
        { 
            /*二乘时间初始化*/
            s_TimeCtrl[i].circular_buf.size = CFM_TIME_2X_COUNT;
            s_TimeCtrl[i].destDev_Num = 3;
            s_TimeCtrl[i].time_type = TIME_SYNC_2x;
            (void)CM_Memcpy(s_TimeCtrl[i].local_addr.IP , sizeof(s_TimeCtrl[i].local_addr.IP), s_TimeCtrl[i].time_addr.Local_4x_Addr.IP, sizeof(s_TimeCtrl[i].time_addr.Local_4x_Addr.IP));
            s_TimeCtrl[i].local_addr.Port = s_TimeCtrl[i].time_addr.Local_4x_Addr.Port; /*本地设备地址*/
            s_TimeCtrl[i].destDev_addr[0] = s_TimeCtrl[i].time_addr.Partner_Addr; /*目标设备地址*/
            s_TimeCtrl[i].destDev_addr[1] = s_TimeCtrl[i].time_addr.Partner_Area_Addr_A; /*目标设备地址*/
            s_TimeCtrl[i].destDev_addr[2] = s_TimeCtrl[i].time_addr.Partner_Area_Addr_B; /*目标设备地址*/
        }
        else
        {
            s_TimeCtrl[i].destDev_Num = i;
            s_TimeCtrl[i].time_type = i;
        }

        s_TimeCtrl[i].isOK = ENUM_CM_FALSE;

        /* 初始化环形缓冲区 */
        rt = CircularBuf_Init(&s_TimeCtrl[i].circular_buf);
        CM_NM_ASSERT(ENUM_CM_TRUE == rt, 0,0,0);
        /*创建本地通信socket*/
        rt = CM_UDP_Socket_Create(&s_TimeCtrl[i].pSock, CM_FALSE, (CM_UINT32)inet_addr(s_TimeCtrl[i].local_addr.IP), s_TimeCtrl[i].local_addr.Port, 0u, (CM_UINT8)1u);
        CM_NM_ASSERT(ENUM_CM_TRUE == rt, 0,0,0);

        s_TimeCtrl[TIME_SYNC_2x].TimeSyncFlag = CM_FALSE;

        /* 创建唯一的线程名称 */
        (void)snprintf(threadName, sizeof(threadName), "TimeSync_%d", i);
        /*创建时间同步线程*/
        rtThread = CM_Thread_Create((CM_THREAD_T*)NULL, (CM_THREAD_FUNC_T)t_Sync_TimeThread, "TimeSync", 0, CM_TASK_PRIORITY_72, (CM_Thread_Arg_Struct_T*)&s_TimeCtrl[i]);
        CM_NM_ASSERT(CM_TRUE == rtThread, 0,0,0);
    }
    rt = ENUM_CM_TRUE;  

    return rt;
}
static ENUM_CM_RETURN CircularBuf_Init(STRU_CIRCULAR_BUFFER_T *p_circular)
{
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;
    /* 检查输入参数是否为空指针 */
    if(NULL != p_circular)
    {
        /* 初始化缓冲区数据计数器为0 */
        p_circular->count = 0;
        /* 初始化写入索引为0 */
        p_circular->index = 0;
        /* 初始化缓冲区指针为NULL */
        p_circular->pBuffer = (CM_INT64 *)CM_Malloc(p_circular->size * sizeof(CM_INT64));
        if(NULL != p_circular->pBuffer)
        {
            rt = ENUM_CM_TRUE;
        }
        else
        {
            /* 缓冲区指针为空，返回错误 */
            rt = ENUM_CM_FALSE;
        }
        
    }
    else
    {
        /* 如果输入参数为空指针，记录错误日志 */
        rt = ENUM_CM_FALSE;
    }

    return rt;
}
/**
 * @brief 清空环形缓冲区
 * 
 * 将环形缓冲区的计数器和索引重置为0，并将缓冲区内的所有数据清零，
 * 实现环形缓冲区的一键清空功能。
 * 
 * @param[in,out] circular_buf 环形缓冲区结构体指针
 * 
 * @note 该函数会:
 *       - 将缓冲区数据计数器(count)重置为0
 *       - 将写入索引(index)重置为0
 *       - 将缓冲区内的所有数据清零
 * 
 * @see STRU_CIRCULAR_BUFFER_T
 */
static void CFM_ClearCircularBuf(STRU_CIRCULAR_BUFFER_T *p_circular)
{
    /* 检查输入参数是否为空指针 */
    if(NULL != p_circular)
    {
        /* 重置缓冲区数据计数器为0 */
        p_circular->count = 0;
        /* 重置写入索引为0 */
        p_circular->index = 0;
        /* 将缓冲区内的所有数据清零 */
        (void)CM_Memset(p_circular->pBuffer, 0, p_circular->size * sizeof(CM_INT64), p_circular->size * sizeof(CM_INT64));
    }
    else
    {
        /* 如果输入参数为空指针，记录错误日志 */
        MSCP_LOG_MSG("circular_buf is NULL\n");
    }
}

static CM_THREAD_FUNC_T t_Sync_TimeThread(IN CM_Thread_Arg_Struct_T* arg)
{
    /*- 变量初始化 */
    STRU_CFM_TIME_CTRL_T* pCtrl = (STRU_CFM_TIME_CTRL_T*)arg;  /* 线程参数 */
    CM_UINT8 buf[100] = { 0u };  /* 接收缓冲区 */
    CM_INT32 len = 0;            /* 数据长度 */
    CM_UINT32 srcIP = 0u;         /* 源IP */
    CM_UINT16 srcPort = 0u;       /* 源端口 */
    CM_UINT64 tick = 0u;     /* 精确时间 */
    CM_UINT64 T1 = 0u;  /* 时钟同步参数 */
    CM_UINT64 T2 = 0u;  /* 时钟同步参数 */
    CM_UINT64 T3 = 0u;  /* 时钟同步参数 */
    CM_UINT64 T4 = 0u;  /* 时钟同步参数 */
    CM_UINT8 i = 0u;
    ENUM_CM_RETURN sendRtn = ENUM_CM_FALSE;

    void* pmask = NULL;
#if QNX
        /*- 本线程锁定在 A53 core 1 */
        pmask = (void*)(0x01u|0x02u);
        (void)ThreadCtl(_NTO_TCTL_RUNMASK, pmask);
#else
    set_thread_affinity(*pmask);
#endif
    MSCP_LOG_MSG("[%d]Time Service Start\n", pCtrl->time_type);

    while (1)
    {
    	CM_ASSERT(1,0,0,0);//与主线程同步宕机
        /*- 阻塞接收时钟同步报文或主线程启动T1发送请求 */
        len = CM_UDP_Recv_Msg(pCtrl->pSock, buf, (CM_INT32)sizeof(buf), &srcIP, &srcPort);
        tick = DFM_GetCycTick();

        /*判断消息类型*/
        switch ((ENUM_TIME_MSG_T)buf[0])
        {
        case ENUM_TIME_START:

            /*- 发送时钟同步T1请求 */
            buf[0] = ENUM_TIME_REQ;
            CM_64ToChar(tick , buf + 1);
            len = 9;
            /*- 发送时钟同步T1请求 */
            for(i = 0u; i < pCtrl->destDev_Num; i++)
            {
            	sendRtn = CM_UDP_Send_Msg(pCtrl->pSock, buf, len, inet_addr(pCtrl->destDev_addr[i].IP), pCtrl->destDev_addr[i].Port);
            	if(ENUM_CM_FALSE == sendRtn)
            	{
            		MSCP_LOG_MSG("Time ARQ senf fial %d\n",i);
            	}
            	else
            	{
            		;
            	}

            }
            break;
        case ENUM_TIME_REQ:
            /*- 接收时钟同步T1响应 */
            if(9 == len)
            {
                    /*- 解析请求报文 */
                    T1 = CM_64FromChar(buf + 1);
                    /*- 生成应答报文 */
                    T2 = tick;
                    buf[0] = (CM_UINT8)ENUM_TIME_ACK;
                    CM_64ToChar(T1, buf + 1);
                    CM_64ToChar(T2, buf + 9);
                    T3 = DFM_GetCycTick();
                    CM_64ToChar(T3, buf + 17);
                    /*- 发送应答报文 */
                    (void)CM_UDP_Send_Msg(pCtrl->pSock, buf, (CM_INT32)25, srcIP, srcPort);
            }
            else
            {
                MSCP_LOG_MSG("Time Service Receive Time Request len = %d\n",len);
            }
            break;
        case ENUM_TIME_ACK:
            /*- 接收时钟同步T2响应 */
            if(25 == len)
            {
                /*返回最终全部时间*/
                buf[0] = ENUM_TIME_RET;
                /*- 解析响应报文 */
                T1 = CM_64FromChar(buf + 1);
                T2 = CM_64FromChar(buf + 9);
                T3 = CM_64FromChar(buf + 17);
                T4 = tick;

                if(TIME_SYNC_2oo2 == pCtrl->time_type)
                {
                    /*二取双向校时 计算offset*/
                    CM_Mutex_Lock(pCtrl->mutex);
                    pCtrl->offset = (CM_INT64)((T2 + T3) - (T4 + T1)) / 2;
                    pCtrl->isOK = ENUM_CM_TRUE;
                    CM_Mutex_Unlock(pCtrl->mutex);
                }
                else if(TIME_SYNC_2x == pCtrl->time_type)
                {
                    /*二取双向校时 响应T2请求*/
                    CM_64ToChar(T1, buf + 1);
                    CM_64ToChar(T2, buf + 9);
                    CM_64ToChar(T3, buf + 17);
                    CM_64ToChar(T4, buf + 25);
                    /*- 发送最终时间 */
                    (void)CM_UDP_Send_Msg(pCtrl->pSock, buf, (CM_INT32)33, srcIP, srcPort);
                }
                else
                {
                    ;/*- 其他类型报文不处理 */
                }
            }
            else
            {
                MSCP_LOG_MSG("Time Service Receive Time Ack len = %d\n",len);
            }
            break;
        case ENUM_TIME_RET:
            /*- 接收时钟同步T4响应 时间具备 可以计算offset*/
            if(33 == len)
            {
                /*- 解析响应报文 */
                T1 = CM_64FromChar(buf + 1);
                T2 = CM_64FromChar(buf + 9);
                T3 = CM_64FromChar(buf + 17);
                T4 = CM_64FromChar(buf + 25);
                
                /*- 计算本次间偏移量 */
                CM_Mutex_Lock(pCtrl->mutex);
                pCtrl->offset = (CM_INT64)((T2 + T3) - (T4 + T1))  / 2;
                pCtrl->isOK = ENUM_CM_TRUE;
                CM_Mutex_Unlock(pCtrl->mutex);
            }
            else
            {
                MSCP_LOG_MSG("Time Service Receive Time Return len = %d\n",len);
            }
            break;
        default:
            break;
        }
    }
    
    return NULL;
}

/**
 * @brief 计算平均偏移量（去除极值后）
 * 
 * 维护一个环形数组，当数组满时进行排序并去除极值后计算平均值
 * 
 * @param offset 当前时间偏移量
 * @param circular_buf 环形数组结构体指针
 * @return 计算出的平均值，如果数组未满则返回当前offset
 */
static CM_INT64 calculate_average_offset(CM_INT64 offset, STRU_CIRCULAR_BUFFER_T *circular_buf)
{
    CM_INT64 average = 0;
    CM_INT32 i = 0, j = 0;
    CM_INT64 temp = 0;
    CM_INT64 sum = 0;
    CM_INT64 temp_buffer[300] = {0};   /* 创建临时数组用于排序 */

    /* 参数检查 */
    if ((NULL == circular_buf) || (circular_buf->size > 300))
    {
    	CM_ASSERT(0,0,0,0);
    }
    else
    {
        /* 将新的offset值添加到环形数组中 */
        circular_buf->pBuffer[circular_buf->index] = offset;
        circular_buf->index = (circular_buf->index + 1) % circular_buf->size;  /* 环形移动索引 */

        /* 更新数组元素计数 */
        if (circular_buf->count < circular_buf->size)
        {
            circular_buf->count++;
            average = 0;
        }
        else
        {
            /* 拷贝数据到临时数组，注意拷贝的字节数 */
            (void)CM_Memcpy(temp_buffer, sizeof(CM_INT64) * circular_buf->count, circular_buf->pBuffer, circular_buf->count * sizeof(CM_INT64));

            /* 使用冒泡排序对数组进行从小到大排序 */
            for (i = 0; i < circular_buf->count - 1; i++)
            {
                for (j = 0; j < circular_buf->count - i - 1; j++)
                {
                    if (temp_buffer[j] > temp_buffer[j + 1])
                    {
                        temp = temp_buffer[j];
                        temp_buffer[j] = temp_buffer[j + 1];
                        temp_buffer[j + 1] = temp;
                    }
                }
            }
            /* 去除一个最大值(最后一个元素)和一个最小值(第一个元素)，计算剩余n个数的平均值 */
            sum = 0;
            for (i = 1; i < circular_buf->count - 1; i++)  /* 跳过最大值和最小值 */
            {
                sum += temp_buffer[i];
            }
            average = sum / (circular_buf->count - 2);
            
            return average;
        }
    }

    return average;
}

/**
 * @brief 获取时间偏移量
 * 
 * 根据指定的时间同步类型获取相应的时间偏移量，并重置获取标志
 * 
 * @param[out] p_avg_offset 平均时间偏移量输出指针
 * @param[out] p_offset 时间偏移量输出指针
 * @param[in] type 时间同步类型（ENUM_TIME_2oo2或ENUM_TIME_2x）
 * 
 * @return ENUM_CM_RETURN
 * @retval ENUM_CM_TRUE  获取成功
 * @retval ENUM_CM_FALSE 获取失败
 */
ENUM_CM_RETURN CFM_Get_Time(OUT CM_INT64 *p_offset,CM_UINT8 type)
{
    ENUM_CM_RETURN ret = ENUM_CM_FALSE;

    /* 检查输入参数是否有效 */
    if(NULL != p_offset)
    {
        /* 加锁保护共享资源访问 */
        CM_Mutex_Lock(s_TimeCtrl[type].mutex);
        
        /* 检查时间同步是否已完成 */
        if (ENUM_CM_TRUE == s_TimeCtrl[type].isOK)
        {
            /* 获取当前时间偏移量 */
            *p_offset = s_TimeCtrl[type].offset;
            /*获取完数值置0 */
            s_TimeCtrl[type].offset = 0;
            /* 重置获取标志，避免重复获取相同数据 */
            s_TimeCtrl[type].isOK = ENUM_CM_FALSE;
            /* 设置返回值为成功 */
            ret = ENUM_CM_TRUE;
        }
        else
        {
            *p_offset = CM_INT64_MAX;
            /* 时间同步未完成，记录错误日志 */
            MSCP_LOG_MSG("Time Service Get Time Offset Failed\n");
            /* 设置返回值为失败 */
            ret = ENUM_CM_FALSE;
        }
        /* 解锁释放共享资源 */
        CM_Mutex_Unlock(s_TimeCtrl[type].mutex);
    }
    else
    {
        /* 输入参数无效，记录错误日志 */
        MSCP_LOG_MSG("Time Service Get Time param is NULL\n");
        /* 设置返回值为失败 */
        ret = ENUM_CM_FALSE;
    }
    /* 返回执行结果 */
    return ret;
}
/**
 * @brief 获取时间偏移量并计算校时结果
 * 
 * 根据时间同步类型获取相应的本地和对端时间偏移量，通过2oo2交换机制获取对端数据，
 * 并根据系统状态和预设门限计算最终的时间调整值。
 * 
 * @param[out] p_avg_offset_2x 2x时间同步类型的平均偏移量输出指针
 * @param[out] p_avg_offset_2oo2 2oo2时间同步类型的平均偏移量输出指针
 * 
 * @note 该函数会根据主从状态和时间偏移量大小决定是否需要调整时钟
 * @see CFM_Get_Time
 * @see SFM_2oo2_Exchange_Currency
 * @see SFM_GetLocal4x2State
 */
void CFM_Get_Offset(CM_INT64 *p_avg_offset_2x, CM_INT64 *p_avg_offset_2oo2)
{
    /* 存储本地和对端的时间偏移量 [本地/对端][2oo2/2x] */
    CM_INT64 offset[2][2] = {{0}}; 
    CM_UINT8 peer_buf[30] = {0};    /* 存储从对端接收的数据缓冲区 */
    CM_UINT8 local_buf[30] = {0};   /* 存储本地发送的数据缓冲区 */
    ENUM_CM_RETURN result = ENUM_CM_FALSE;

    /* 检查输出参数是否有效 */
    if((NULL != p_avg_offset_2x) && (NULL != p_avg_offset_2oo2))
    {
        /* 获取本地时间偏移量 */
    	result = CFM_Get_Time(&offset[TIME_OFFSET_LOCAL][TIME_SYNC_2oo2], TIME_SYNC_2oo2);

    	if(result == ENUM_CM_TRUE)
    	{
    		;
    	}
    	else
    	{
    		offset[TIME_OFFSET_LOCAL][TIME_SYNC_2oo2] = CM_INT64_MAX;
    	}

    	result = CFM_Get_Time(&offset[TIME_OFFSET_LOCAL][TIME_SYNC_2x], TIME_SYNC_2x);

        if(result == ENUM_CM_TRUE)
        {
        	;
        }
        else
        {
        	offset[TIME_OFFSET_LOCAL][TIME_SYNC_2x] = CM_INT64_MAX;
        }

        /* 将本地时间偏移量打包到缓冲区 8字节2取偏移量 +8字节2乘偏移量 */
        CM_64ToChar(offset[TIME_OFFSET_LOCAL][TIME_SYNC_2oo2], local_buf);
        CM_64ToChar(offset[TIME_OFFSET_LOCAL][TIME_SYNC_2x], local_buf + 8);

        /* 通过2oo2交换机制获取对端数据 */
        (void)SFM_2oo2_Exchange_Currency(local_buf, 16,  peer_buf, 16, ENUM_2oo2_SYNC);
        /* 解析对端时间偏移量 */
        offset[TIME_OFFSET_PEER][TIME_SYNC_2oo2] = (CM_INT64)CM_64FromChar(peer_buf);
        offset[TIME_OFFSET_PEER][TIME_SYNC_2x] = (CM_INT64)CM_64FromChar(peer_buf + 8);
        MSCP_LOG_MSG("first get offset 2x %lld  %lld   2oo2 %lld %lld\n",offset[TIME_OFFSET_LOCAL][TIME_SYNC_2x], offset[TIME_OFFSET_PEER][TIME_SYNC_2x], offset[TIME_OFFSET_LOCAL][TIME_SYNC_2oo2],offset[TIME_OFFSET_PEER][TIME_SYNC_2oo2]);
        /* 计算2x时间同步类型的最终时间调整值 */
        *p_avg_offset_2x = CFM_Get_2x_offset(offset[TIME_OFFSET_LOCAL][TIME_SYNC_2x], offset[TIME_OFFSET_PEER][TIME_SYNC_2x]);

        /* 计算2oo2时间同步类型的最终时间调整值 */
        *p_avg_offset_2oo2 = CFM_Get_2oo2_offset(offset[TIME_OFFSET_LOCAL][TIME_SYNC_2oo2], offset[TIME_OFFSET_PEER][TIME_SYNC_2oo2]);
    }
    else
    {
        /* 参数为空指针，记录错误日志 */
        MSCP_LOG_MSG("Time Service Get Time Offset Failed param is NULL\n");
        CM_ASSERT(0,0,0,0);
    }
}
/**
 * @brief 计算平均时间偏移量
 * 
 * 根据本地和对端的时间偏移量计算平均值，用于时间同步精度优化。
 * 当本地和对端都有有效偏移量时，取两者的平均值；
 * 当只有一方有有效偏移量时，直接使用该偏移量；
 * 当双方都无有效偏移量时，返回0。
 * 
 * @param[in] local_offse 本地时间偏移量
 * @param[in] peer_offset 对端时间偏移量
 * 
 * @return CM_INT64 计算得到的平均时间偏移量
 * @retval 0 本地和对端偏移量都为0，或计算异常
 * @retval 其他值 计算得到的平均偏移量
 * 
 * @note 该函数用于提高时间同步的准确性和稳定性
 * @see CFM_Get_2x_offset
 * @see CFM_Get_2oo2_offset
 */
static CM_INT64 CFM_Get_Avg_2oo2offset(CM_INT64 local_offse, CM_INT64 peer_offset)
{
    CM_INT64 avg_offset = 0;  /* 计算得到的平均时间偏移量 */


    /* 当本地和对端都有有效偏移量时，计算平均值 */
    if((0 != local_offse) && (0 != peer_offset))
    {
        /* 取本地和对端偏移量的平均值 */
        avg_offset = (local_offse - peer_offset) / 2;
        MSCP_LOG_MSG("myOffset = %lld,The calibration result is the average value of 2oo2 dual machines\n", avg_offset);
    }
    /* 当只有本地有有效偏移量时，直接使用本地偏移量 */
    else if(0 != local_offse)
    {
        /* 直接使用本地偏移量作为平均值 */
        avg_offset = local_offse;
        MSCP_LOG_MSG("The calibration result is the local calibration result\n");
    }
    /* 当只有对端有有效偏移量时，直接使用对端偏移量 */
    else if(0 != peer_offset)
    {
        /* 直接使用对端偏移量作为平均值 */
        avg_offset = -peer_offset;
        MSCP_LOG_MSG("The calibration result is the calibration result of the neighboring machine\n");
    }
    /* 当双方都无有效偏移量时，返回0 */
    else
    {
        /* 本地和对端偏移量都为0，返回0 */
        avg_offset = 0;
        MSCP_LOG_MSG("Failed to calibrate this period\n");
    }

    /* 返回计算得到的平均偏移量 */
    return avg_offset;
}
static CM_INT64 CFM_Get_Avg_2x2offset(CM_INT64 local_offse, CM_INT64 peer_offset)
{
    CM_INT64 avg_offset = CM_INT64_MAX;  /* 计算得到的平均时间偏移量 */


    /* 当本地和对端都有有效偏移量时，计算平均值 */
    if(((local_offse > CM_INT64_MIN) && (local_offse < CM_INT64_MAX)) && ((peer_offset > CM_INT64_MIN) && (peer_offset < CM_INT64_MAX)))
    {
        /* 取本地和对端偏移量的平均值 */
        avg_offset = (local_offse + peer_offset) / 2;
        MSCP_LOG_MSG("myOffset = %lld,The calibration result is the average value of 2oo2 dual machines\n", avg_offset);
    }
    /* 当只有本地有有效偏移量时，直接使用本地偏移量 */
    else if((local_offse > CM_INT64_MIN) && (local_offse < CM_INT64_MAX))
    {
        /* 直接使用本地偏移量作为平均值 */
        avg_offset = local_offse;
        MSCP_LOG_MSG("The calibration result is the local calibration result\n");
    }
    /* 当只有对端有有效偏移量时，直接使用对端偏移量 */
    else if((peer_offset > CM_INT64_MIN) && (peer_offset < CM_INT64_MAX))
    {
        /* 直接使用对端偏移量作为平均值 */
        avg_offset = peer_offset;
        MSCP_LOG_MSG("The calibration result is the calibration result of the neighboring machine\n");
    }
    /* 当双方都无有效偏移量时，返回0 */
    else
    {
        /* 返回无效值 */
        avg_offset = CM_INT64_MAX;
        MSCP_LOG_MSG("Failed to calibrate this period\n");
    }

    /* 返回计算得到的平均偏移量 */
    return avg_offset;
}
/**
 * @brief 计算2x时间同步偏移量
 * 
 * 根据本地和对端的2x时间偏移量计算最终的时间调整值，用于2x时间同步。
 * 该函数首先计算平均偏移量，然后根据系统状态和预设门限判断是否需要进行时间调整，
 * 并设置相应的时间同步标志位。
 * 
 * @param[in] local_offse 本地时间偏移量
 * @param[in] peer_offset 对端时间偏移量
 * 
 * @return CM_INT64 计算得到的时间调整值
 * @retval 0 不需要时间调整
 * @retval 正值 需要延长时间周期
 * @retval 负值 需要缩短时间周期
 * 
 * @note 该函数仅在非主系状态下进行时间调整计算
 * @see SFM_2x2_TM_FIX_VAL_NS
 * @see s_TimeCtrl
 * @see SFM_GetLocal4x2State
 */
static CM_INT64 CFM_Get_2x_offset(CM_INT64 local_offse, CM_INT64 peer_offset)
{
    CM_INT64 rtn_offset = 0;              /* 返回的时间调整值 */
    CM_INT64 avg_2x_offset = 0;           /* 平均时间偏移量 */
    CM_INT64 aveOffset = 0;               /* 经过滤波处理后的平均时间偏移量 */
    ENUM_4x2_STATE_T state = SFM_GetLocal4x2State(); /* 获取当前2x2状态 */
    CM_INT64 cyctime_ns = (CM_INT64)(g_PFM_Cfg.CYC_TIME) * CM_MILLION; /* 周期时间(ns) */
    static CM_UINT32 TimeSyncToleranceCount = 0u; /* 时间同步容忍次数*/


    /* 非主系才需要调整时钟 */
    if(ENUM_4x2_MASTER != state)
    {
        /* 计算本地和对端的平均时间偏移量 */
        avg_2x_offset = CFM_Get_Avg_2x2offset(local_offse, peer_offset);
        MSCP_LOG_MSG("2x2 get offset  = %lld cyc = %u\n",avg_2x_offset, SFM_2x2_GetSysCount());
        /* 判断时间同步是否完成，设置相应的时间同步标志 */
        if(CM_ABS(avg_2x_offset) >= SFM_2x2_TM_FIX_VAL_NS * 2)
        {
        	if((CM_TRUE == CM_ATOMIC_LOAD(&s_TimeCtrl[TIME_SYNC_2x].TimeSyncFlag)) && (TimeSyncToleranceCount < SFM_TIME_SYNC_TOLERANCE_COUNT))
        	{
        		/* 上次时间同步成功 进行容忍次数计数*/
        		TimeSyncToleranceCount++;
        	}
        	else
        	{
        		TimeSyncToleranceCount = 0u;
        	}

        	if(TimeSyncToleranceCount >= SFM_TIME_SYNC_TOLERANCE_COUNT)
        	{
                /* 平均偏移量超过阈值的2倍，标记时间同步失败 */
                CM_ATOMIC_STORE(&s_TimeCtrl[TIME_SYNC_2x].TimeSyncFlag, CM_FALSE);
                MSCP_LOG_MSG("*** time sync too big\n");
        	}

        }
        else
        {
            /* 平均偏移量在允许范围内，标记时间同步成功 */
            CM_ATOMIC_STORE(&s_TimeCtrl[TIME_SYNC_2x].TimeSyncFlag, CM_TRUE);
            TimeSyncToleranceCount = 0u;
        }

        /* 根据系统状态决定是否清空或处理环形缓冲区 */
        if(avg_2x_offset != CM_INT64_MAX)
        {
            if(ENUM_4x2_OFFLINE == state)
            {
                aveOffset = avg_2x_offset;
                /* 系统处于离线或预主状态时，清空环形缓冲区 */
                CFM_ClearCircularBuf(&s_TimeCtrl[TIME_SYNC_2x].circular_buf);
            }
            else
            {
                /* 系统处于正常工作状态时，对平均偏移量进行滤波处理 */
                aveOffset = (calculate_average_offset(avg_2x_offset, &s_TimeCtrl[TIME_SYNC_2x].circular_buf));
                if(CM_ABS(aveOffset) >= SFM_2x2_TM_FIX_VAL_NS)
                {
                	s_TimeCtrl[TIME_SYNC_2x].circular_buf.count = 0;
                }
                else
                {
                	;
                }
            }
        }
        else
        {
        	aveOffset = 0;
        }
        MSCP_LOG_MSG("avg offset = %lld\n",aveOffset);

        /* 判断是否需要调大时钟超过一个周期 */
        if (aveOffset >= cyctime_ns)
        {
            /* 本次只做周期基准时间调整，不调整周期定时器（将偏移量四舍五入到整周期）*/
            rtn_offset = ((CM_INT64)(aveOffset + cyctime_ns / 2) / cyctime_ns) * cyctime_ns;
            MSCP_LOG_MSG("Increase the clock by more than one cycle *pOffset = %lld\n",rtn_offset);
        }
        /* 判断是否需要调小时钟超过一个周期 */
        else if (aveOffset <= -cyctime_ns)
        {
            /* 本次只做周期基准时间调整，不调整周期定时器（将偏移量四舍五入到整周期）*/
            rtn_offset = ((CM_INT64)(aveOffset - cyctime_ns / 2) / cyctime_ns) * cyctime_ns;
            MSCP_LOG_MSG("Set the clock more than one cycle*pOffset = %lld\n",rtn_offset);
        }
        /* 判断是否需要调大时钟不超过一个周期 */
        else if (aveOffset >= (CM_INT64)SFM_2x2_TM_FIX_VAL_NS)
        {
            /* 本周期定时器延长10ms */
            rtn_offset = SFM_2x2_TM_FIX_VAL_NS;
            MSCP_LOG_MSG("The interval timer is extended by 10ms\n");
        }
        /* 判断是否需要调小时钟不超过一个周期 */
        else if (aveOffset <= -(CM_INT64)SFM_2x2_TM_FIX_VAL_NS)
        {
            /* 本周期定时器缩短10ms */
            rtn_offset = -SFM_2x2_TM_FIX_VAL_NS;
            MSCP_LOG_MSG("The interval timer is shortened by 10ms\n");
        }
        else
        {
            /* 不需要调整时钟 */
            rtn_offset = 0;
        }
    }
    else
    {
        /* 主系不需要调整时钟 */
        rtn_offset = 0;
    }

    /* 返回计算得到的时间调整值 */
    return rtn_offset;
}
/**
 * @brief 计算2oo2时间同步偏移量
 * 
 * 根据本地和对端的2oo2时间偏移量计算最终的时间调整值，用于2oo2时间同步。
 * 该函数首先计算平均偏移量，然后根据预设门限判断是否需要进行时间调整。
 * 当平均偏移量超过门限值时，进行相应的时间调整；否则不调整。
 * 
 * @param[in] local_offset 本地时间偏移量
 * @param[in] peer_offset 对端时间偏移量
 * 
 * @return CM_INT64 计算得到的时间调整值
 * @retval 0 偏差在允许范围内，不需要调整时钟
 * @retval -CM_MILLION 本地时钟过慢，需要缩短周期时间1ms
 * @retval CM_MILLION 本地时钟过快，需要延长周期时间1ms
 * 
 * @note 该函数用于2oo2时间同步机制中的时钟调整计算
 * @see SFM_2oo2_TM_FIX_VAL_NS
 * @see CFM_Get_Avg_offset
 */
static CM_INT64 CFM_Get_2oo2_offset(CM_INT64 local_offset, CM_INT64 peer_offset)
{
    CM_INT64 rtn_offset = 0;        /* 返回的时间调整值 */
    CM_INT64 ave_offset = 0;        /* 平均时间偏移量 */

    /* 计算本地和对端的平均时间偏移量 */
    ave_offset = CFM_Get_Avg_2oo2offset(local_offset, peer_offset);

    MSCP_LOG_MSG("2oo2 get offset  = %lld\n",ave_offset);

    /* 检查本次测得的偏移量是否在合理范围内(±10ms) */
    if (CM_ABS(ave_offset) < (10 * CM_MILLION))
    {
        /* 对平均偏移量再次进行滤波处理，去除噪声影响 */
        ave_offset = calculate_average_offset(ave_offset, &s_TimeCtrl[TIME_SYNC_2oo2].circular_buf);
        
        if(CM_ABS(ave_offset) >= SFM_2oo2_TM_FIX_VAL_NS)
        {
        	s_TimeCtrl[TIME_SYNC_2oo2].circular_buf.count = 0;
        }
        else
        {

        }

        /* 判断本机时钟偏差并设置调整值 */
        if (ave_offset > SFM_2oo2_TM_FIX_VAL_NS)
        {
            /* 本地时钟过慢，需要缩短本周期时间1ms */
            rtn_offset = -CM_MILLION;
        }
        /* 判断本机时钟是否过快 */
        else if (ave_offset < -SFM_2oo2_TM_FIX_VAL_NS)
        {
            /* 本地时钟过快，需要延长本周期时间1ms */
            rtn_offset = CM_MILLION;
        }
        else
        {
            /* 偏差在允许范围内(±3ms)，不需要调整时钟 */
            rtn_offset = 0;
        }
    }
    else
    {
        /* 偏移量超出合理范围(±10ms)，认为测量异常，不进行调整 */
        rtn_offset = 0;
    }

    /* 返回计算得到的时间调整值 */
    return rtn_offset;
}
/**
 * @brief 获取时间同步状态标志
 * 
 * 获取系统时间同步完成状态标志，用于判断时间同步是否已完成且在有效范围内。
 * 该标志由时间同步算法根据计算出的时间偏移量与预设门限值比较后设置。
 * 
 * @param[in] void 无参数
 * 
 * @return CM_BOOL 时间同步状态
 * @retval CM_TRUE  时间同步完成且在允许误差范围内
 * @retval CM_FALSE 时间同步未完成或超出允许误差范围
 * 
 * @note 该函数通过原子操作读取标志位，保证多线程环境下的数据一致性
 */
CM_UINT8 CFM_GetTimeSyncFlag(void)
{
    ENUM_4x2_STATE_T state = SFM_GetLocal4x2State();  /* 获取当前2x2系统的状态 */
    CM_UINT8 time_flag = CM_FALSE;                        /* 时间同步状态标志 */

    if(ENUM_4x2_MASTER == state)
    {
        /* 主系默认时间同步成功，直接返回CM_TRUE */
        time_flag = CM_TRUE;
    }
    else
    {
        /* 非主系从时间控制结构中读取时间同步标志 */
        time_flag = CM_ATOMIC_LOAD(&s_TimeCtrl[TIME_SYNC_2x].TimeSyncFlag);
    }

    return time_flag;
}
/**
 * @brief 发送时间同步请求消息
 * 
 * 向2oo2和2x时间同步通道发送时间同步启动请求消息，触发时间同步过程。
 * 通过UDP协议向配置的本地地址和端口发送ENUM_TIME_START消息。
 * 
 * @param[in] void 无参数
 * 
 * @return 无
 * 
 * @note 该函数会同时向2oo2和2x两个时间同步通道发送启动请求
 * @see ENUM_TIME_START
 * @see s_TimeCtrl
 */
void CFM_SendLocalARQ(void)
{
    static CM_UINT8 buf[10] = {0u};             /* 发送缓冲区 */
    ENUM_CM_RETURN ret = ENUM_CM_FALSE;          /* 函数返回值 */
    ENUM_4x2_STATE_T state = SFM_GetLocal4x2State();

    /* 设置消息类型为时间同步启动请求 */
    buf[0] = ENUM_TIME_START;

    if(ENUM_4x2_MASTER == state)
    {
        /* 向2x时间同步通道发送启动请求消息 */
        ret = CM_UDP_Send_Msg(s_TimeCtrl[TIME_SYNC_2x].pSock, buf, 10, inet_addr(s_TimeCtrl[TIME_SYNC_2x].local_addr.IP), s_TimeCtrl[TIME_SYNC_2x].local_addr.Port);
        CM_ASSERT(ENUM_CM_TRUE == ret,0,0,0);
    }
    else
    {
    	;
    }
    /* 向2oo2时间同步通道发送启动请求消息 */
    ret = CM_UDP_Send_Msg(s_TimeCtrl[TIME_SYNC_2oo2].pSock, buf, 10, inet_addr(s_TimeCtrl[TIME_SYNC_2oo2].local_addr.IP), s_TimeCtrl[TIME_SYNC_2oo2].local_addr.Port);
    CM_ASSERT(ENUM_CM_TRUE == ret,0,0,0);
}


/*获取本地输出比较结果，输出校验与应用跟随比较结果，比较一致返回CM_TRUE,失败返回CM_FALSE*/
CM_UINT8 CFM_GetSyncFailFlag(void)
{
	return SFM_GetLocalSyncFailFlag();
}

/*获取失步次数，没有收到输出校验与应用跟随数据的周期计数*/
CM_UINT32 CFM_GetOutOfSync(void)
{
	return SFM_GetLocalOutOfSync();
}
/*获取本地同步健康度:全部参数同步成功，离线升备，或升主条件，同步成功返回CM_TRUE,失败返回CM_FALSE*/
CM_UINT8 CFM_GetSyncHealth(void)
{
	return SFM_GetLocalSyncHealth();
}
