#include "cpri_delay.h"
#include "ucp_drv_common.h"
#include "ucp_utility.h"
#include "ucp_cpri.h"
#include "ucp_param.h"
#include "mtimer_com.h"
#include "hw_cpri.h"
#include "phy_para.h"
#include "ucp_printf.h"
#include "ecs_rfm_dm_mgt.h"

extern stPhyScsPara*		phyPara;
stCpriLinkStatus	cpriLinkStatus;
uint32_t			gCpriDelayOamSetFlag = 0;
// 告警标志
//uint32_t gCpriAlarmFlag = CPRI_NO_ALARM;		// cpri告警标志，后续应该上报给OM
//uint32_t gCpriAlarmMeasureCnt = 0;

void cpri_delay_init()
{
	stCpriDelayMeasure* pCpriDelay = NULL; // pEcsDmLocalMgt->pCpriDelay;
	uint16_t gpsOffset = 0;
//#ifdef DISTRIBUTED_BS
    EcsRfmDmLocalMgt_t* pEcsDmLocalMgt = get_ecs_rfm_dm_local_mgt();
	stMtimerPara* pMtimerPara = pEcsDmLocalMgt->pMtimerPara[MTIMER_CPRI_ID];
	pCpriDelay = pEcsDmLocalMgt->pCpriDelay;

	uint32_t addr = (uint32_t)&(phyPara[pMtimerPara->scsId].gpsOffset);
	gpsOffset = do_read_volatile_short(addr);
//#endif
	if (NULL == pCpriDelay)
	{
		return;
	}
    do_write(CPRI_DELAY_ADDR, 0);
    do_write(CPRI_ADVANCE_ADDR, 0);
    do_write(CPRI_TDD_ADVANCE_ADDR, 0);

    memset(pCpriDelay, 0, sizeof(stCpriDelayMeasure));
    pCpriDelay->delayReTOffset	= CPRI_RE_TOFFSET;  // ns
    pCpriDelay->delayReT2A		= CPRI_T2A;         // ns
    pCpriDelay->delayDma        = EDMA_OFFSET;      // ns

    pCpriDelay->cpri10msOffset	  = CPRI_RE_TOFFSET + CPRI_INT_DELAY*2;
    pCpriDelay->cpri10msRxOffset  = CPRI_RE_TOFFSET + CPRI_INT_DELAY*2; // + 2;
    pCpriDelay->cpriTddOffset	  = CPRI_RE_TOFFSET + CPRI_INT_DELAY*2 + EDMA_OFFSET;
	
    do_write(CPRI_ADVANCE_ADDR, pCpriDelay->cpri10msOffset);
    do_write(CPRI_TDD_ADVANCE_ADDR, pCpriDelay->cpriTddOffset);
	do_write(CPRI_DELAY_ADDR, pCpriDelay->cpri10msRxOffset);
	
	pCpriDelay->cpri10ms2PP1sTxOffset = pCpriDelay->cpri10msOffset + gpsOffset*1000;
	pCpriDelay->cpri10ms2PP1sRxOffset = gpsOffset*1000 - pCpriDelay->cpri10msRxOffset;
	pCpriDelay->cpriTdd2PP1sOffset = gpsOffset*1000 + pCpriDelay->cpriTddOffset;
	
    do_write(CPRI_TX_ADVANCE_PP1S_ADDR, pCpriDelay->cpri10ms2PP1sTxOffset);
    do_write(CPRI_RX_ADVANCE_PP1S_ADDR, pCpriDelay->cpri10ms2PP1sRxOffset);
	do_write(CPRI_TDD_ADVANCE_PP1S_ADDR, pCpriDelay->cpriTdd2PP1sOffset);
}

void cpri_link_status_init()
{
    *((uint32_t*)(&cpriLinkStatus)) = 0;
}

// cpri时延校准
void cpri_delay_measurement()
{
    EcsRfmDmLocalMgt_t* pEcsDmLocalMgt = get_ecs_rfm_dm_local_mgt();
	stCpriPara* pCpriPara = NULL; // pEcsDmLocalMgt->pCpriPara;
	stCpriDelayMeasure* pCpriDelay = NULL; // pEcsDmLocalMgt->pCpriDelay;
	stFhAlarmStat* pAlarmStat = pEcsDmLocalMgt->pAlarmStatus;

//#ifdef DISTRIBUTED_BS
	pCpriPara = pEcsDmLocalMgt->pCpriPara;
	pCpriDelay = pEcsDmLocalMgt->pCpriDelay;
//#endif
	if (NULL == pCpriPara || NULL == pCpriDelay)
	{
		return;
	}

	pCpriDelay->delayMeasureCnt++;

	int32_t stat_frm_tx_cnt_del_pos = CPRI_FRAME_TX_RNDTRIP_DEL & 0x7F;		// cycles in basic frame
	int32_t stat_frm_tx_cnt_del_x = (CPRI_FRAME_TX_RNDTRIP_DEL>>8) & 0xFF;	// basic frames part
	int32_t stat_frm_tx_cnt_del_z = (CPRI_FRAME_TX_RNDTRIP_DEL>>16) & 0xFF;	// hyper frames part

	// round trip delay, core clk
	int32_t t_roundtrip_delay = stat_frm_tx_cnt_del_pos + stat_frm_tx_cnt_del_x * pCpriPara->cpri_rate_coff * 4
		+ stat_frm_tx_cnt_del_z * pCpriPara->cpri_rate_coff * 4 * 256;
	pCpriDelay->delayRndTrip = 1000000000.0 * t_roundtrip_delay / pCpriPara->core_clk; // us

	// cpri ip delay, core clk
	int32_t t_cpri_ip_tx = CPRI_IP_DELAY_TX & 0xFFFF;
	int32_t t_cpri_ip_rx = CPRI_IP_DELAY_RX & 0xFFFF;

	pCpriDelay->delayIpTx = 1000000000.0 * t_cpri_ip_tx / pCpriPara->core_clk; // us
	pCpriDelay->delayIpRx = 1000000000.0 * t_cpri_ip_rx / pCpriPara->core_clk; // us

	// adj buf delay, adjBufDepth = 5;
	int32_t t_tx_adj = CPRI_ADJ_OFFSET_TX & 0x1F + 2;
	int32_t t_rx_adj = CPRI_ADJ_OFFSET_RX & 0x1F + 2;

	pCpriDelay->delayAdjTx = 1000000000.0 * t_tx_adj / pCpriPara->core_clk; // us
	pCpriDelay->delayAdjRx = 1000000000.0 * t_rx_adj / pCpriPara->core_clk; // us

	// RE offset

	// serdes delay
	pCpriDelay->delaySerdesTx = 1000000000.0 * CPRI_TX_SERDES_DELAY / pCpriPara->pcs_serdes_clk / 32; // us
	pCpriDelay->delaySerdesRx = 1000000000.0 * CPRI_RX_SERDES_DELAY / pCpriPara->pcs_serdes_clk / 32; // us

	// pcs delay
	if (0 == pCpriPara->encode_flag)		// 8B/10B
	{
		//T8b10b,tx  = stat_sh_tx_delay(average) * pcs_fine_delay_clk +  sh_gb_pos_tx(average)/serdes_width * serdes_clk + 1/2*core_clk
		int32_t sh_tx_delay = 0;
		CPRI_PCS_ADDR_CFG = SH_DELAY_TX;//ADDR
		CPRI_PCS_CTRL_CFG = 0X1;//Read
		sh_tx_delay = CPRI_PCS_DATA_RX_STAT & 0xFF;

		int32_t sh_gb_pos_tx = 0;
		CPRI_PCS_ADDR_CFG = SH_GB_POS_TX;//ADDR
		CPRI_PCS_CTRL_CFG = 0X1;//Read
		sh_tx_delay = CPRI_PCS_DATA_RX_STAT & 0xFF;

		//T8b10b,rx  = stat_sh_rx_delay(average) * pcs_fine_delay_clk +  sh_gb_pos_rx(average)/serdes_width * serdes_clk + comma_delays*core_clk - 1/2* core_clk
		int32_t sh_rx_delay = 0;
		CPRI_PCS_ADDR_CFG = SH_DELAY_RX;//ADDR
		CPRI_PCS_CTRL_CFG = 0X1;//Read
		sh_rx_delay = CPRI_PCS_DATA_RX_STAT & 0xFF;

		int32_t sh_gb_pos_rx = 0;
		CPRI_PCS_ADDR_CFG = SH_GB_POS_RX;//ADDR
		CPRI_PCS_CTRL_CFG = 0X1;//Read
		sh_gb_pos_rx = CPRI_PCS_DATA_RX_STAT & 0xFF;

		int32_t comma_delays = 0; //??
		CPRI_PCS_ADDR_CFG = DELAY_RX;//ADDR
		CPRI_PCS_CTRL_CFG = 0X1;//Read
		comma_delays = (CPRI_PCS_DATA_RX_STAT >> 4) & 0x7 + (CPRI_PCS_DATA_RX_STAT & 0xF);

		pCpriDelay->delayPcsTx = 1000000000.0 * sh_tx_delay / pCpriPara->pcs_fine_delay_clk + 1000000000.0 * sh_gb_pos_tx / 32 / pCpriPara->pcs_serdes_clk
			+ 1000000000.0 / 2 / pCpriPara->core_clk;
		pCpriDelay->delayPcsRx = 1000000000.0 * sh_rx_delay / pCpriPara->pcs_fine_delay_clk + 1000000000.0 * sh_gb_pos_rx / 32 / pCpriPara->pcs_serdes_clk
			+ 1000000000.0 * comma_delays / pCpriPara->core_clk - 1000000000.0 / 2 / pCpriPara->core_clk;
	}
	else								// 64B/66B
	{
		if (0 == pCpriPara->rs_fec_flag)	// with no RS-FEC
		{
#if 0
			// T64b66b,tx  = stat_sh_tx_delay(average) * pcs_fine_delay_clk +  sh_gb_pos_tx(average)/32 * serdes_clk + ½*core_clk
			int32_t sh_tx_delay = 0;
			do_write(&CPRI_PCS_ADDR_CFG, SH_DELAY_TX);//ADDR
			do_write(&CPRI_PCS_CTRL_CFG, 0x1);//Read
			sh_tx_delay = do_read_volatile(&CPRI_PCS_DATA_RX_STAT) & 0xFF;

			int32_t sh_gb_pos_tx = 0;
			do_write(&CPRI_PCS_ADDR_CFG, SH_GB_POS_TX);//ADDR
			do_write(&CPRI_PCS_CTRL_CFG, 0x1);//Read
			sh_gb_pos_tx = do_read_volatile(&CPRI_PCS_DATA_RX_STAT) & 0xFF;

			// T64b66b,rx  = stat_sh_rx_delay(average) * pcs_fine_delay_clk +  (sh_gb_pos_rx(average) – slip_cnt)/32 * serdes_clk - ½ * core_clk
			int32_t sh_rx_delay = 0;
			do_write(&CPRI_PCS_ADDR_CFG, SH_DELAY_RX);//ADDR
			do_write(&CPRI_PCS_CTRL_CFG, 0x1);//Read
			sh_rx_delay = do_read_volatile(&CPRI_PCS_DATA_RX_STAT) & 0xFF;

			int32_t sh_gb_pos_rx = 0;
			do_write(&CPRI_PCS_ADDR_CFG, SH_GB_POS_RX);//ADDR
			do_write(&CPRI_PCS_CTRL_CFG, 0x1);//Read
			sh_gb_pos_rx = do_read_volatile(&CPRI_PCS_DATA_RX_STAT) & 0xFF;

			int32_t slip_cnt = 0;
			do_write(&CPRI_PCS_ADDR_CFG, DELAY_RX);//ADDR
			do_write(&CPRI_PCS_CTRL_CFG, 0x1);//Read
			slip_cnt = (do_read_volatile(&CPRI_PCS_DATA_RX_STAT) >> 8) & 0x7F;

#else
			// T64b66b,tx  = stat_sh_tx_delay(average) * pcs_fine_delay_clk +  sh_gb_pos_tx(average)/32 * serdes_clk + ½*core_clk
			int32_t sh_tx_delay = PCS_SH_TX_DELAY;
			int32_t sh_gb_pos_tx = PCS_SH_GB_POS_TX;
			
			// T64b66b,rx  = stat_sh_rx_delay(average) * pcs_fine_delay_clk +  (sh_gb_pos_rx(average) – slip_cnt)/32 * serdes_clk - ½ * core_clk
			int32_t sh_rx_delay = PCS_SH_RX_DELAY;
			int32_t sh_gb_pos_rx = PCS_SH_GB_POS_RX;
			int32_t slip_cnt = PCS_SLIP_CNT;
#endif
			debug_write((DBG_DDR_IDX_DRV_BASE+1001), sh_tx_delay); // 0xfa4
			debug_write((DBG_DDR_IDX_DRV_BASE+1002), sh_gb_pos_tx); // 0xfa8
			debug_write((DBG_DDR_IDX_DRV_BASE+1003), sh_rx_delay); // 0xfac
			debug_write((DBG_DDR_IDX_DRV_BASE+1004), sh_gb_pos_rx); // 0xfb0
			debug_write((DBG_DDR_IDX_DRV_BASE+1005), slip_cnt);		// 0xfb4
			
			pCpriDelay->delayPcsTx = 1000000000.0 * sh_tx_delay / pCpriPara->pcs_fine_delay_clk + 1000000000.0 * sh_gb_pos_tx / 32 / pCpriPara->pcs_serdes_clk
				+ 1000000000.0 / 2 / pCpriPara->core_clk;
			pCpriDelay->delayPcsRx = 1000000000.0 * sh_rx_delay / pCpriPara->pcs_fine_delay_clk + 1000000000.0 * (sh_gb_pos_rx-slip_cnt) / 32 / pCpriPara->pcs_serdes_clk
				- 1000000000.0 / 2 / pCpriPara->core_clk;
		}
		else							// with RS_FEC
		{
			// T64b66b,tx  = (30 - cfg_bit_delay/66)*core_clk + 1 serdes_clk + (1+stat_buf_tx_delay_fine) * pcs_fine_delay_clk
			int32_t cfg_bit_delay = 0;
			CPRI_PCS_ADDR_CFG = CFG_TX;//ADDR
			CPRI_PCS_CTRL_CFG = 0x1;//Read
			cfg_bit_delay = (CPRI_PCS_DATA_RX_STAT >> 9) & 0x7F;

			int32_t tx_delay_fine = 0;
			CPRI_PCS_ADDR_CFG = BUF_STAT_TX;//ADDR
			CPRI_PCS_CTRL_CFG = 0x1;//Read
			tx_delay_fine = CPRI_PCS_DATA_RX_STAT & 0xFF;

			pCpriDelay->delayPcsTx = 1000000000.0 * (30.0 - cfg_bit_delay/66.0) / pCpriPara->core_clk + 1000000000.0 / pCpriPara->pcs_serdes_clk
				+ 1000000000.0 * (1 + tx_delay_fine) / pCpriPara->pcs_fine_delay_clk; // us

			// T64b66b,rx  = (1+stat_buf_rx_delay_fine)*pcs_fine_clk + (164.5 – slip_cnt/66)*core_clk + 2*serdes_clk
			int32_t rx_delay_fine = 0;
			CPRI_PCS_ADDR_CFG = BUF_STAT_RX;//ADDR
			CPRI_PCS_CTRL_CFG = 0x1;//Read
			rx_delay_fine = CPRI_PCS_DATA_RX_STAT & 0xFF;

			int32_t slip_cnt = 0;
			CPRI_PCS_ADDR_CFG = DELAY_RX;//ADDR
			CPRI_PCS_CTRL_CFG = 0x1;//Read
			slip_cnt = (CPRI_PCS_DATA_RX_STAT>>8) & 0x7F;

			pCpriDelay->delayPcsRx = 1000000000.0 * (1 + rx_delay_fine) / pCpriPara->pcs_fine_delay_clk + 1000000000.0 * (164.5-slip_cnt/66.0) / pCpriPara->core_clk
				+ 1000000000.0 * 2 / pCpriPara->pcs_serdes_clk; // us
		}
	}

	// cable delay
	pCpriDelay->delayCable = (pCpriDelay->delayRndTrip - (pCpriDelay->delayIpTx + pCpriDelay->delayIpRx + pCpriDelay->delayAdjTx + pCpriDelay->delayAdjRx + pCpriDelay->delayReTOffset
					+ pCpriDelay->delayPcsTx + pCpriDelay->delayPcsRx + pCpriDelay->delaySerdesTx + pCpriDelay->delaySerdesRx))/2.0;
	if (0 >= pCpriDelay->delayCable)
	{
		pCpriDelay->delayCable = 0;
	}
	//else
	{
		debug_write((DBG_DDR_IDX_DRV_BASE+993), t_roundtrip_delay); // 0xf84
		debug_write((DBG_DDR_IDX_DRV_BASE+994), pCpriDelay->delayRndTrip); // 0xf88
		debug_write((DBG_DDR_IDX_DRV_BASE+995), pCpriDelay->delayIpTx); // 0xf8c
		debug_write((DBG_DDR_IDX_DRV_BASE+996), pCpriDelay->delayIpRx); // 0xf90
		debug_write((DBG_DDR_IDX_DRV_BASE+997), pCpriDelay->delayAdjTx); // 0xf94
		debug_write((DBG_DDR_IDX_DRV_BASE+998), pCpriDelay->delayAdjRx); // 0xf98
		debug_write((DBG_DDR_IDX_DRV_BASE+999), pCpriDelay->delaySerdesTx); // 0xf9c
		debug_write((DBG_DDR_IDX_DRV_BASE+1000), pCpriDelay->delaySerdesRx); // 0xfa0
		//debug_write((DBG_DDR_IDX_DRV_BASE+265), sh_tx_delay); // 0x424
		//debug_write((DBG_DDR_IDX_DRV_BASE+266), sh_gb_pos_tx); // 0x428
		//debug_write((DBG_DDR_IDX_DRV_BASE+267), sh_rx_delay); // 0x42c
		//debug_write((DBG_DDR_IDX_DRV_BASE+268), sh_gb_pos_rx); // 0x430
		//debug_write((DBG_DDR_IDX_DRV_BASE+269), slip_cnt);		// 0x434
		debug_write((DBG_DDR_IDX_DRV_BASE+1006), pCpriDelay->delayPcsTx);		// 0xfb8
		debug_write((DBG_DDR_IDX_DRV_BASE+1007), pCpriDelay->delayPcsRx);		// 0xfbc
		debug_write((DBG_DDR_IDX_DRV_BASE+1008), pCpriDelay->delayCable);		// 0xfc0
	}

	if (1 == pCpriDelay->delayMeasureCnt) // 测量第一次
	{
		pCpriDelay->delayRndCableMax = pCpriDelay->delayCable * 2;
		pCpriDelay->delayRndCableMin = pCpriDelay->delayCable * 2;
	}
	else
	{
		if (pCpriDelay->delayRndCableMax < (pCpriDelay->delayCable * 2))
		{
			pCpriDelay->delayRndCableMax = pCpriDelay->delayCable * 2;
		}
		if (pCpriDelay->delayRndCableMin > (pCpriDelay->delayCable * 2))
		{
			pCpriDelay->delayRndCableMin = pCpriDelay->delayCable * 2;
		}
		if ((pCpriDelay->delayRndCableMax - pCpriDelay->delayRndCableMax) > CPRI_RNDCABLE_DELAY_PRECISION)
		{
			pCpriDelay->delayRndCableAlarm = 1; // cable delay precision alarm
			pAlarmStat->alarmFlag = CPRI_ALARM_CABLE;
		}
	}

	// round trip delay excluding cable delay
	pCpriDelay->delayRndTripExCable = pCpriDelay->delayRndTrip - 2 * pCpriDelay->delayCable;
	debug_write((DBG_DDR_IDX_DRV_BASE+1009), pCpriDelay->delayRndTripExCable);		// 0xfc4
	if (pCpriDelay->delayRndTripExCable > CPRI_RNDTRIP_EXCABLE_DELAY_MAX)
	{
		pCpriDelay->delayRndTripAlarm = 1; // round trip delay alarm;
		pAlarmStat->alarmFlag = CPRI_ALARM_RNDTRIP;
	}

	__ucps2_synch(0);
	uint32_t cpri_10ms_offset = 0;
	uint32_t cpri_10ms_rx_offset = 0;
	uint32_t cpri_tdd_offset = 0;
	cpri_10ms_offset = pCpriDelay->delayIpTx + pCpriDelay->delayAdjTx + pCpriDelay->delayPcsTx + pCpriDelay->delaySerdesTx + pCpriDelay->delayCable + pCpriDelay->delayReT2A; // +T2A??
	cpri_10ms_rx_offset = pCpriDelay->delayIpRx + pCpriDelay->delayAdjRx + pCpriDelay->delayPcsRx + pCpriDelay->delaySerdesRx + pCpriDelay->delayCable;
	__ucps2_synch(0);
	debug_write((DBG_DDR_IDX_DRV_BASE+1010), cpri_10ms_offset);			// 0xfc8
	debug_write((DBG_DDR_IDX_DRV_BASE+1011), cpri_10ms_rx_offset);		// 0xfcc

	// 64次取平均值
	int32_t averCnt = pCpriDelay->delayMeasureCnt & 0x3F;
	pCpriDelay->cpri10msOffsetSam[averCnt] = cpri_10ms_offset;
	pCpriDelay->cpri10msRxOffsetSam[averCnt] = cpri_10ms_rx_offset;

	if (64 > pCpriDelay->delayMeasureCnt)	// 小于64次，直接返回，测量值无效
	{
		return;
	}

	uint64_t offsetSum = 0;
	uint64_t offsetRxSum = 0;
	for (int32_t i = 0; i < 64; i++)
	{
		offsetSum += pCpriDelay->cpri10msOffsetSam[i];
		offsetRxSum += pCpriDelay->cpri10msRxOffsetSam[i];
	}
	__ucps2_synch(0);
	cpri_10ms_offset = (offsetSum >> 6);// / 1000;		// ns -> us
	cpri_10ms_rx_offset = (offsetRxSum >> 6);// / 1000;	// ns -> us
	
	__ucps2_synch(0);
	cpri_tdd_offset = cpri_10ms_offset + pCpriDelay->delayDma;	// ns
	pCpriDelay->delayMeausreValid = 1;

	__ucps2_synch(0);
	debug_write((DBG_DDR_IDX_DRV_BASE+1012), cpri_10ms_offset);		// 0xfd0
	debug_write((DBG_DDR_IDX_DRV_BASE+1013), cpri_tdd_offset);		// 0xfd4
	debug_write((DBG_DDR_IDX_DRV_BASE+1014), cpri_10ms_rx_offset);	// 0xfd8
#if 0
	//uint32_t tempOffset;
	//tempOffset = (uint32_t)(((float)cpri_10ms_offset/1000)+0.5);	// ns -> us
	pCpriDelay->cpri10msOffset = (cpri_10ms_offset < FIBER_MIN_DELAY) ? (FIBER_MIN_DELAY+CPRI_INT_DELAY) : (cpri_10ms_offset+CPRI_INT_DELAY);
	
	//tempOffset = (uint32_t)(((float)cpri_10ms_rx_offset/1000)+0.5);	// ns -> us
	pCpriDelay->cpri10msRxOffset = (cpri_10ms_rx_offset < FIBER_MIN_DELAY) ? (FIBER_MIN_DELAY+CPRI_INT_DELAY) : (cpri_10ms_rx_offset+CPRI_INT_DELAY);
	
	pCpriDelay->cpriTddOffset = pCpriDelay->cpri10msOffset + CPRI_INT_DELAY + EDMA_OFFSET;
	
	do_write(CPRI_ADVANCE_ADDR, pCpriDelay->cpri10msOffset);
	do_write(CPRI_TDD_ADVANCE_ADDR, pCpriDelay->cpriTddOffset);
	do_write(CPRI_DELAY_ADDR, pCpriDelay->cpri10msRxOffset);
#else
	pCpriDelay->cpriTxOffset = cpri_10ms_offset;
	pCpriDelay->cpriRxOffset = cpri_10ms_rx_offset;
	//pCpriDelay->cpriTddOffset = (uint32_t)(((float)cpri_tdd_offset/1000)+0.5);
#endif

	return;
}

// cpri link delay for ck
void cpri_delay_measurement_ck()
{
	stCpriPara* pCpriPara = NULL; // pEcsDmLocalMgt->pCpriPara;
	stCpriDelayMeasure* pCpriDelay = NULL; // pEcsDmLocalMgt->pCpriDelay;

//#ifdef DISTRIBUTED_BS
    EcsRfmDmLocalMgt_t* pEcsDmLocalMgt = get_ecs_rfm_dm_local_mgt();
	pCpriPara = pEcsDmLocalMgt->pCpriPara;
	pCpriDelay = pEcsDmLocalMgt->pCpriDelay;
//#endif
	if (NULL == pCpriPara || NULL == pCpriDelay)
	{
		return;
	}

	pCpriDelay->delayMeasureCnt++;

	int32_t stat_frm_tx_cnt_del_pos = CPRI_FRAME_TX_RNDTRIP_DEL & 0x7F;		// cycles in basic frame
	int32_t stat_frm_tx_cnt_del_x = (CPRI_FRAME_TX_RNDTRIP_DEL>>8) & 0xFF;	// basic frames part
	int32_t stat_frm_tx_cnt_del_z = (CPRI_FRAME_TX_RNDTRIP_DEL>>16) & 0xFF;	// hyper frames part

	// round trip delay, core clk
	int32_t t_roundtrip_delay = stat_frm_tx_cnt_del_pos + stat_frm_tx_cnt_del_x * pCpriPara->cpri_rate_coff * 4
		+ stat_frm_tx_cnt_del_z * pCpriPara->cpri_rate_coff * 4 * 256;
	pCpriDelay->delayRndTrip = 1000000000.0 * t_roundtrip_delay / pCpriPara->core_clk; // ns

	debug_write((DBG_DDR_IDX_DRV_BASE+992), t_roundtrip_delay); 		// 0xf80
	debug_write((DBG_DDR_IDX_DRV_BASE+993), pCpriDelay->delayRndTrip);	// 0xf88
	
	return;
}


void update_cpri_link_status()
{
    EcsRfmDmLocalMgt_t* pEcsDmLocalMgt = get_ecs_rfm_dm_local_mgt();
	uint32_t linkStat = CPRI_FRAME_RX_L1_STAT;

	cpriLinkStatus.lofFlag = (linkStat >> 3) & 0x1;
	cpriLinkStatus.losFlag = (linkStat >> 2) & 0x1;
	cpriLinkStatus.sdiFlag = (linkStat >> 1) & 0x1;
	cpriLinkStatus.raiFlag = linkStat & 0x1;

	if (0 != *((uint32_t*)&cpriLinkStatus))
	{
		pEcsDmLocalMgt->pAlarmStatus->alarmFlag = CPRI_ALARM_LINKSTATUS;
		// 上报给om
	}
}

stCpriSetDelayRsp gCpriSetDelayRep;
stCpriSetDelayRsp* set_cpri_link_delay(stCpriSetLinkDelay* pCpriSetDelay)
{
	stCpriDelayMeasure* pCpriDelay = NULL; // pEcsDmLocalMgt->pCpriDelay;
	memset(&gCpriSetDelayRep, 0, sizeof(stCpriSetDelayRsp));
	gCpriSetDelayRep.u8fiber_port = pCpriSetDelay->u8fiber_port;

//#ifdef DISTRIBUTED_BS
	EcsRfmDmLocalMgt_t* pEcsDmLocalMgt = get_ecs_rfm_dm_local_mgt();
	pCpriDelay = pEcsDmLocalMgt->pCpriDelay;
//#endif
	if (NULL == pCpriDelay)
	{
		gCpriSetDelayRep.u8result = 0;
		return &gCpriSetDelayRep;
	}

	pCpriDelay->cpriTxOffset = pCpriSetDelay->u32dl_frame_offset;
	pCpriDelay->cpriRxOffset = pCpriSetDelay->u32ul_frame_offset;
	pCpriDelay->cpriUlFrmDataOffset = pCpriSetDelay->u32ul_data_frame_offset;
	debug_write((DBG_DDR_IDX_DRV_BASE+1012), pCpriDelay->cpriTxOffset);		// 0xfd0
	debug_write((DBG_DDR_IDX_DRV_BASE+1014), pCpriDelay->cpriRxOffset);		// 0xfd8
	debug_write((DBG_DDR_IDX_DRV_BASE+1015), pCpriDelay->cpriUlFrmDataOffset);		// 0xfdc

	gCpriSetDelayRep.u8result = 1;

	gCpriDelayOamSetFlag = 1;
	
	return &gCpriSetDelayRep;
}

void get_cpri_link_delay(uint8_t u8fiber_port, stCpriGetLinkDelay* pCpriGetDelay)
{
	if (NULL == pCpriGetDelay)
	{
		return;
	}
	stCpriDelayMeasure* pCpriDelay = NULL; // pEcsDmLocalMgt->pCpriDelay;

//#ifdef DISTRIBUTED_BS
	EcsRfmDmLocalMgt_t* pEcsDmLocalMgt = get_ecs_rfm_dm_local_mgt();
	pCpriDelay = pEcsDmLocalMgt->pCpriDelay;
//#endif
	if (NULL == pCpriDelay)
	{
		pCpriGetDelay->u8result = 0;	// fail
		return;
	}

	pCpriGetDelay->u8fiber_port = u8fiber_port;
	pCpriGetDelay->u8result = 1;
	pCpriGetDelay->u32dl_frame_offset = pCpriDelay->cpriTxOffset;
	pCpriGetDelay->u32ul_frame_offset = pCpriDelay->cpriRxOffset;
	pCpriGetDelay->u32ul_data_frame_offset = pCpriDelay->cpriUlFrmDataOffset;
	
	return;
}

void get_cpri_rndtrip_delay(uint8_t u8fiber_port, stCpriGetRndDelay* pCpriRndDealy)
{
	if (NULL == pCpriRndDealy)
	{
		return;
	}
	stCpriDelayMeasure* pCpriDelay = NULL; // pEcsDmLocalMgt->pCpriDelay;

//#ifdef DISTRIBUTED_BS
	EcsRfmDmLocalMgt_t* pEcsDmLocalMgt = get_ecs_rfm_dm_local_mgt();
	pCpriDelay = pEcsDmLocalMgt->pCpriDelay;
//#endif
	if (NULL == pCpriDelay)
	{
		pCpriRndDealy->u8result = 0;	// fail
		return;
	}

    pCpriRndDealy->u8fiber_port = u8fiber_port;
	pCpriRndDealy->u8result = 1;		// success
	pCpriRndDealy->u32t14_val = pCpriDelay->delayRndTrip;

	return;
}

stCpriFrameHeadOffsetRsp stCpriFrameHeadOff;
stCpriFrameHeadOffsetRsp* set_frame_head_offset(stCpriFrameHeadOffsetReq* pCpriFrameHeadOffset)
{
	memset(&stCpriFrameHeadOff, 0, sizeof(stCpriFrameHeadOff));		
	if (NULL == pCpriFrameHeadOffset)
	{
		stCpriFrameHeadOff.u8result = 0;
		return &stCpriFrameHeadOff;
	}
	uint32_t addr = 0;
	for (int8_t i = 0; i < PHY_SCS_MAX_NUM; i++)
	{
		addr = (uint32_t)&(phyPara[i].gpsOffset);
		do_write_short(addr, pCpriFrameHeadOffset->u16frame_head_offset);
	}
    stCpriFrameHeadOff.u8result = 1;
    return &stCpriFrameHeadOff;
}

void get_cpri_framehead_offset(stCpriGetFrameHeadOffset* pCpriFrameHeadOffset)
{
	if (NULL == pCpriFrameHeadOffset)
	{
		return;
	}
	uint32_t addr = (uint32_t)&(phyPara[0].gpsOffset);
	pCpriFrameHeadOffset->u16frame_head_offset = do_read_volatile_short(addr);
	pCpriFrameHeadOffset->u8result = 1;
	return;
}

void get_cpri_delay(uint32_t* delay)
{
    EcsRfmDmLocalMgt_t* pEcsDmLocalMgt = get_ecs_rfm_dm_local_mgt();
	stCpriDelayMeasure* pCpriDelay = pEcsDmLocalMgt->pCpriDelay;
	
	*delay = pCpriDelay->cpriRxOffset;
}

void get_cpri_advance(uint32_t* advance)
{
    EcsRfmDmLocalMgt_t* pEcsDmLocalMgt = get_ecs_rfm_dm_local_mgt();
	stCpriDelayMeasure* pCpriDelay = pEcsDmLocalMgt->pCpriDelay;
	
	*advance = pCpriDelay->cpriTxOffset;
}

void get_cpri_frame_data_offset(uint32_t* offset)
{
    EcsRfmDmLocalMgt_t* pEcsDmLocalMgt = get_ecs_rfm_dm_local_mgt();
	stCpriDelayMeasure* pCpriDelay = pEcsDmLocalMgt->pCpriDelay;
	
    *offset = pCpriDelay->cpriUlFrmDataOffset;
}



