tEplKernel PUBLIC EplTimerSynckSetLossOfSyncTolerance2Ns (DWORD dwLossOfSyncTolerance2Ns_p)
{
tEplKernel      Ret = kEplSuccessful;


    EplTimerSynckInstance_l.m_dwLossOfSyncTolerance2Ns = dwLossOfSyncTolerance2Ns_p;

    if (dwLossOfSyncTolerance2Ns_p > 0)
    {
        EplTimerSynckInstance_l.m_dwLossOfSyncTimeout2 = EplTimerSynckInstance_l.m_dwConfiguredTimeDiff
                + OMETH_NS_2_TICKS(EplTimerSynckInstance_l.m_dwLossOfSyncTolerance2Ns);
    }
    else
    {
        EplTimerSynckInstance_l.m_dwLossOfSyncTimeout2 = 0;
    }

    return Ret;

}
//------------------------------------------------------------------------------
void openmac_timerIrqEnable(UINT timer_p, UINT32 pulseWidthNs_p)
{
    UINT    offset;
    UINT32  value;

    switch (timer_p)
    {
        case HWTIMER_SYNC:
            offset = OPENMAC_TIMER_OFFSET_CTRL;
            value = 1;
            break;

        case HWTIMER_EXT_SYNC:
            offset = OPENMAC_TIMER_OFFSET_2ND_CTRL;
            value = 1 | (OMETH_NS_2_TICKS(pulseWidthNs_p) << 1);
            break;

        default:
            return;
    }

    IOWR_32DIRECT(OPENMAC_TIMER_BASE, offset, value);
}
static tEplKernel EdrvCyclicProcessTxBufferList(void)
{
tEplKernel      Ret = kEplSuccessful;
tEdrvTxBuffer*  pTxBuffer = NULL;
DWORD            udwAbsTime; //absolute time accumulator
BOOL             fFirstPkt = TRUE; //flag to identify first packet
DWORD            udwMacTimeEntry = EDRV_GET_MAC_TIME(); //MAC TIME AT FUNCTION CALL
//DWORD            udwMacTimePlusOffset = udwMacTimeEntry + EdrvCyclicInstance_l.m_dwTxProcDur; //plus offset
DWORD            udwCycleMin = 0; //absolute minimum cycle time
DWORD            udwCycleMax = 0; //absolute maximum cycle time
DWORD            udwNextOffNs = 0; //next earliest tx time
DWORD            udwNextTimerIrqNs = EdrvCyclicInstance_l.m_dwCycleLenUs * 1000UL; //time of next timer irq

    if( EdrvCyclicInstance_l.m_fNextCycleValid == FALSE )
    {
        //use current time + negative shift to set a valid next cycle
        EdrvCyclicInstance_l.m_dwNextCycleTime = udwMacTimeEntry + OMETH_US_2_TICKS(EDRVCYC_NEG_SHIFT_US);

        //next timer IRQ correction
        udwNextTimerIrqNs -= OMETH_TICKS_2_NS(EdrvCyclicInstance_l.m_dwTxProcDur);

        EdrvCyclicInstance_l.m_fNextCycleValid = TRUE;

    }
    else
    {
        //cycle is valid, compensate next timer irq

        //calculate time difference of Next SoC - approx. entry of this function
        DWORD udwDiff;
        DWORD udwDiffNs;

        udwDiff = EdrvCyclicInstance_l.m_dwNextCycleTime - udwMacTimeEntry;

        if( udwDiff & 0x80000000UL )
        {
            udwDiff = udwMacTimeEntry - EdrvCyclicInstance_l.m_dwNextCycleTime;
            udwDiffNs = OMETH_TICKS_2_NS(udwDiff);
            udwNextTimerIrqNs -= (EDRVCYC_NEG_SHIFT_US * 1000UL + udwDiffNs);
            Ret = EdrvCyclicCycleTimeViolation(udwNextTimerIrqNs);
            goto CycleDone;
        }

        //substract TX buffer list processing from cycle time
        udwNextTimerIrqNs -= OMETH_TICKS_2_NS(EdrvCyclicInstance_l.m_dwTxProcDur);

        udwDiffNs = OMETH_TICKS_2_NS(udwDiff);

        if( udwDiffNs > (EDRVCYC_NEG_SHIFT_US * 1000UL) )
        {
            //time difference is larger negative shift
            udwNextTimerIrqNs += (udwDiffNs - EDRVCYC_NEG_SHIFT_US * 1000UL);
        }
        else if( udwDiffNs > (EDRVCYC_MIN_SHIFT_US * 1000UL) )
        {
            //time difference is shorter than negative shift but larger than minimum
            udwNextTimerIrqNs -= (EDRVCYC_NEG_SHIFT_US * 1000UL - udwDiffNs);
        }
        else
        {
            //time difference is too short => cycle violation!
            udwNextTimerIrqNs -= (EDRVCYC_NEG_SHIFT_US * 1000UL - udwDiffNs);
            Ret = EdrvCyclicCycleTimeViolation(udwNextTimerIrqNs);
            goto CycleDone;
        }
    }

    //set accumulator for cycle window calculation
    udwAbsTime = EdrvCyclicInstance_l.m_dwNextCycleTime; //get cycle start time

    //set limits to verify if time triggered tx is within cycle
    // note: otherwise openMAC would be confused
    udwCycleMin = EdrvCyclicInstance_l.m_dwNextCycleTime; //minimum limit
    udwCycleMax = EdrvCyclicInstance_l.m_dwNextCycleTime + \
            OMETH_US_2_TICKS(EdrvCyclicInstance_l.m_dwCycleLenUs); //maximum limit

    //loop through TX buffer list
    while ((pTxBuffer = EdrvCyclicInstance_l.m_paTxBufferList[EdrvCyclicInstance_l.m_uiCurTxBufferEntry]) != NULL)
    {
        //compare TX buffer time offset with next offset (considers IPG and last packet length)
        //note: otherwise openMAC is confused if time-trig TX starts within other time-trig TX!
        if( (fFirstPkt == FALSE) && (udwNextOffNs > pTxBuffer->m_dwTimeOffsetNs) )
        {
            udwAbsTime += OMETH_NS_2_TICKS(udwNextOffNs); //accumulate offset
        }
        else
        {
            udwAbsTime += OMETH_NS_2_TICKS(pTxBuffer->m_dwTimeOffsetNs); //accumulate offset
        }
        fFirstPkt = FALSE; //first packet is surely out...

        //verify if packet TX start time is within cycle window
        if( (udwAbsTime - udwCycleMin) > (udwCycleMax - udwCycleMin) )
        {
            //packet is outside of the window
            Ret = EdrvCyclicCycleTimeViolation(udwNextTimerIrqNs);
            goto CycleDone;
        }

        //pTxBuffer->m_dwTimeOffsetNs = udwAbsTime | 1; //lowest bit enables time triggered send
        //set the absolute TX start time, and OR the lowest bit to give Edrv a hint
        pTxBuffer->m_dwTimeOffsetAbsTk = udwAbsTime | 1; //lowest bit enables time triggered send

        Ret = EdrvSendTxMsg(pTxBuffer);
        if (Ret != kEplSuccessful)
        {
            goto Exit;
        }

        //set the absolute TX start time to zero
        // -> If the TX buffer is reused as manual TX, EdrvSendTxMsg is not confused!
        pTxBuffer->m_dwTimeOffsetAbsTk = 0;

        //calculate the length of the sent packet, add IPG and thus know the next earliest TX time
        {
            DWORD udwLength = pTxBuffer->m_uiTxMsgLen;

            //consider padding!
            if( udwLength < 60UL )
            {
                udwLength = 60UL;
            }

            // ( pre + header + payload + padding + crc ) * 80ns/byte + 960ns = next TX time
            udwNextOffNs = EDRVCYC_BYTETIME_NS * (EDRVCYC_PREAMB_SIZE + ETH_CRC_SIZE + udwLength) + EDRVCYC_IPG_NS;
        }

        //switch to next TX buffer
        EdrvCyclicInstance_l.m_uiCurTxBufferEntry++;
    }

    //set up next timer interrupt
    Ret = EplTimerHighReskModifyTimerNs(&EdrvCyclicInstance_l.m_TimerHdlCycle,
        udwNextTimerIrqNs,
        EdrvCyclicCbTimerCycle,
        0L,
        FALSE);

    if (Ret != kEplSuccessful)
    {
        PRINTF("%s: EplTimerHighReskModifyTimerNs ret=0x%X\n", __func__, Ret);
        goto Exit;
    }

CycleDone:
    //calculate next cycle
    EdrvCyclicInstance_l.m_dwNextCycleTime += OMETH_US_2_TICKS(EdrvCyclicInstance_l.m_dwCycleLenUs);

Exit:
    return Ret;
}