status_t ENET_ReadFrame()

in lib/nxp/drivers/fsl_enet.c [1498:1670]


status_t ENET_ReadFrame(ENET_Type *base, enet_handle_t *handle, uint8_t *data, uint32_t length, uint8_t channel)
{
    assert(handle);

    uint32_t len    = 0;
    uint32_t offset = 0;
    uint32_t control;
    bool isLastBuff             = false;
    enet_rx_bd_ring_t *rxBdRing = (enet_rx_bd_ring_t *)&handle->rxBdRing[channel];
    enet_rx_bd_struct_t *rxDesc;
    status_t result = kStatus_Fail;
    uint16_t index  = rxBdRing->rxGenIdx;
    bool suspend    = false;
#ifdef ENET_PTP1588FEATURE_REQUIRED
    uint32_t buffer;
    uint32_t bufferAdd;
#endif /* ENET_PTP1588FEATURE_REQUIRED  */

    /* Suspend and command for rx. */
    if (base->DMA_CH[channel].DMA_CHX_STAT & ENET_DMA_CH_DMA_CHX_STAT_RBU_MASK)
    {
        suspend = true;
    }

    /* For data-NULL input, only update the buffer descriptor. */
    if ((!data))
    {
        do
        {
            /* Get the control flag. */
            rxDesc             = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
            rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
            control            = rxDesc->control;
            /* Updates the receive buffer descriptors. */
            ENET_UpdateRxDescriptor(rxDesc, NULL, NULL, handle->rxintEnable, handle->doubleBuffEnable);

            /* Find the last buffer descriptor for the frame. */
            if (control & ENET_RXDESCRIP_WR_LD_MASK)
            {
#ifdef ENET_PTP1588FEATURE_REQUIRED
                /* Reinit for the context descritor which has been updated by DMA. */
                rxDesc = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
                if (rxDesc->control & ENET_RXDESCRIP_WR_CTXT_MASK)
                {
                    if (!handle->doubleBuffEnable)
                    {
                        buffer = handle->rxbuffers[rxBdRing->rxGenIdx];
                        ENET_UpdateRxDescriptor(rxDesc, (void *)buffer, NULL, handle->rxintEnable,
                                                handle->doubleBuffEnable);
                    }
                    else
                    {
                        buffer    = handle->rxbuffers[2 * rxBdRing->rxGenIdx];
                        bufferAdd = handle->rxbuffers[2 * rxBdRing->rxGenIdx + 1];
                        ENET_UpdateRxDescriptor(rxDesc, (void *)buffer, (void *)bufferAdd, handle->rxintEnable,
                                                handle->doubleBuffEnable);
                    }
                    rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
                }
#endif /*  ENET_PTP1588FEATURE_REQUIRED */
                break;
            }
        } while (rxBdRing->rxGenIdx != index);

        result = kStatus_Success;
    }
    else
    {
#ifdef ENET_PTP1588FEATURE_REQUIRED
        enet_ptp_time_data_t ptpTsData;
        bool ptp1588 = false;
#endif /* ENET_PTP1588FEATURE_REQUIRED */

        while ((!isLastBuff))
        {
            /* The last buffer descriptor of a frame. */
            rxDesc             = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
            rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
#ifdef ENET_PTP1588FEATURE_REQUIRED
            if (rxDesc->control & ENET_RXDESCRIP_WR_FD_MASK)
            {
                ptp1588 = ENET_Ptp1588ParseFrame((uint8_t *)rxDesc->buff1Addr, &ptpTsData, false);
            }
#endif
            if (rxDesc->control & ENET_RXDESCRIP_WR_LD_MASK)
            {
                /* This is a valid frame. */
                isLastBuff = true;
                if (length == (rxDesc->control & ENET_RXDESCRIP_WR_PACKETLEN_MASK))
                {
                    /* Copy the frame to user's buffer. */
                    len = (rxDesc->control & ENET_RXDESCRIP_WR_PACKETLEN_MASK) - offset;
                    if (len > rxBdRing->rxBuffSizeAlign)
                    {
                        memcpy(data + offset, (void *)rxDesc->buff1Addr, rxBdRing->rxBuffSizeAlign);
                        offset += rxBdRing->rxBuffSizeAlign;
                        memcpy(data + offset, (void *)rxDesc->buff2Addr, len - rxBdRing->rxBuffSizeAlign);
                    }
                    else
                    {
                        memcpy(data + offset, (void *)rxDesc->buff1Addr, len);
                    }

                    result = kStatus_Success;
                }

                /* Updates the receive buffer descriptors. */
                ENET_UpdateRxDescriptor(rxDesc, NULL, NULL, handle->rxintEnable, handle->doubleBuffEnable);
#ifdef ENET_PTP1588FEATURE_REQUIRED
                /* Store the rx timestamp which is in the next buffer descriptor of the last
                 * descriptor of a frame. */
                rxDesc = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;

                /* Reinit for the context descritor which has been updated by DMA. */
                if (rxDesc->control & ENET_RXDESCRIP_WR_CTXT_MASK)
                {
                    if (ptp1588)
                    {
                        ENET_StoreRxFrameTime(base, handle, rxDesc, channel, &ptpTsData);
                    }

                    if (!handle->doubleBuffEnable)
                    {
                        buffer = handle->rxbuffers[rxBdRing->rxGenIdx];
                        ENET_UpdateRxDescriptor(rxDesc, (void *)buffer, NULL, handle->rxintEnable,
                                                handle->doubleBuffEnable);
                    }
                    else
                    {
                        buffer    = handle->rxbuffers[2 * rxBdRing->rxGenIdx];
                        bufferAdd = handle->rxbuffers[2 * rxBdRing->rxGenIdx + 1];
                        ENET_UpdateRxDescriptor(rxDesc, (void *)buffer, (void *)bufferAdd, handle->rxintEnable,
                                                handle->doubleBuffEnable);
                    }
                    rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
                }
                base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR = base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR;
#endif /* ENET_PTP1588FEATURE_REQUIRED */
            }
            else
            {
                /* Store a frame on several buffer descriptors. */
                isLastBuff = false;
                /* Length check. */
                if (offset >= length)
                {
                    /* Updates the receive buffer descriptors. */
                    ENET_UpdateRxDescriptor(rxDesc, NULL, NULL, handle->rxintEnable, handle->doubleBuffEnable);
                    break;
                }

                memcpy(data + offset, (void *)rxDesc->buff1Addr, rxBdRing->rxBuffSizeAlign);
                offset += rxBdRing->rxBuffSizeAlign;
                if ((rxDesc->buff2Addr) && (handle->doubleBuffEnable))
                {
                    memcpy(data + offset, (void *)rxDesc->buff2Addr, rxBdRing->rxBuffSizeAlign);
                    offset += rxBdRing->rxBuffSizeAlign;
                }

                /* Updates the receive buffer descriptors. */
                ENET_UpdateRxDescriptor(rxDesc, NULL, NULL, handle->rxintEnable, handle->doubleBuffEnable);
            }
        }
    }

    /* Set command for rx when it is suspend. */
    if (suspend)
    {
        base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR = base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR;
    }

    return result;
}