/*
 * Copyright 2021 MindMotion Microelectronics Co., Ltd.
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "board_init.h"

/*
 * Definitions.
 */
#define ENET_RX_BUFLEN                     1518u      /* Configure the frame length of a received frame. */
#define ENET_RX_NUM                        5u         /* The configured number of received descriptor that can be used for receiving. */
#define ENET_PHY_ADDR                      0x01       /* PHY address. */
#define ENET_PHY_CONTROLREG                0u         /* PHY control register address. */
#define ENET_PHY_STATUSREG                 1u         /* PHY status register address. */
#define ENET_PHY_RESET                     0x8000     /* Set PHY reset, use in ENET_PHY_CR registers */
#define ENET_PHY_SPEED100M                 0x2000     /* Set PHY speed. */
#define ENET_PHY_FULLDUPLEX                0x0100     /* Set PHY duplex mode about full duplex. */
#define ENET_PHY_LINK                      0x0004     /* PHY link-up. */
#define ENET_PHY_UNIDIRECTIONAL            0x0080     /* PHY has the ability to encode and transmit data from PHY through MII interface, regardless of whether PHY has determined that an effective link has been connected and established. */
#define ENET_PHY_AUTONEGOTIATION           0x1000     /* PHY auto negotiation. */
#define ENET_ADDR_FILTER_NUM               1u         /* Select MAC address filter number from 0~5. */

/*
 * Variables.
 */
ENET_RxDmaDesp_Type RxDmaDespTab[ENET_RX_NUM];
uint8_t app_enet_rxbuf[ENET_RX_NUM][ENET_RX_BUFLEN];
uint8_t app_enet_rxbackup[ENET_RX_NUM][ENET_RX_BUFLEN];
uint32_t app_enet_rxcnt = 0u;

/*
 * Declerations.
 */
void app_enet_init_smi();
void app_enet_init_mac();
void app_enet_init_dma();
void app_enet_rx();

/*
 * Functions.
 */
int main(void)
{
    BOARD_Init();

    app_enet_init_smi();
    app_enet_init_mac();
    app_enet_init_dma();
    app_enet_rx();

    while (1)
    {
        if (app_enet_rxcnt == ENET_RX_NUM)
        {
            for (uint32_t i = 0u; i < app_enet_rxcnt; i++)
            {
                memcpy(app_enet_rxbackup[i], app_enet_rxbuf[i], RxDmaDespTab[i].FL);  /* copy receive's data to receive backup array. */
                printf("app_enet_rx() done.\r\n");
                for (uint32_t j = 0u; j < RxDmaDespTab[i].FL; j++)
                {
                    printf("0x%02x, ", app_enet_rxbackup[i][j]);
                }
                printf("\r\n\r\n");
            }
            app_enet_rxcnt = 0u;
            ENET_LinkRxDmaDesp(BOARD_DEBUG_ENET_PORT, RxDmaDespTab, &app_enet_rxbuf[0u][0u], ENET_RX_BUFLEN, ENET_RX_NUM);
        }
    }
}

/* Initlization enet smi. */
void app_enet_init_smi()
{
    uint32_t *m_enet_smi_data = 0u;
    /* Initialization smi. */
    ENET_InitSmi(BOARD_DEBUG_ENET_PORT, ENET_SmiClockAlt_Alt1);
    ENET_WriteMacPhyReg(BOARD_DEBUG_ENET_PORT, ENET_PHY_ADDR, ENET_PHY_CONTROLREG, ENET_PHY_RESET);   /* Rest PHY. */
    ENET_ReadMacPhyReg(BOARD_DEBUG_ENET_PORT, ENET_PHY_ADDR, ENET_PHY_CONTROLREG, m_enet_smi_data);
    while ( 0u != (*m_enet_smi_data & ENET_PHY_RESET) )
    {
        ENET_ReadMacPhyReg(BOARD_DEBUG_ENET_PORT, ENET_PHY_ADDR, ENET_PHY_CONTROLREG, m_enet_smi_data);
    }
    uint16_t temp = ENET_PHY_SPEED100M | ENET_PHY_FULLDUPLEX;
    temp &= ~ENET_PHY_AUTONEGOTIATION;   /* Not use autonegotiation PHY. */
    ENET_WriteMacPhyReg(BOARD_DEBUG_ENET_PORT,ENET_PHY_ADDR, ENET_PHY_CONTROLREG, temp);  /* Config PHY. */
    ENET_ReadMacPhyReg(BOARD_DEBUG_ENET_PORT, ENET_PHY_ADDR, ENET_PHY_STATUSREG, m_enet_smi_data);
    while( 0u == (*m_enet_smi_data & ENET_PHY_LINK) || ( 0u != (*m_enet_smi_data & ENET_PHY_UNIDIRECTIONAL) ) )  /* Wait PHY link up. */
    {
        ENET_ReadMacPhyReg(BOARD_DEBUG_ENET_PORT, ENET_PHY_ADDR, ENET_PHY_STATUSREG, m_enet_smi_data);
    }
}

/* Initlization enet mac. */
void app_enet_init_mac()
{
    ENET_Init_Type enet_init;

    /* Initialization mac. */
    enet_init.SourceAddrReplace = ENET_SourceAddrReplaceAlt_Alt0;
    enet_init.StripCRC = false;
    enet_init.DisableWatchdog = false;
    enet_init.DisableJabberCount = false;
    enet_init.InterframeGap = ENET_InterFrameGap_96;
    enet_init.EnableLoopback = false;
    enet_init.DuplexMode = ENET_DuplexMode_FullDuplex;
    enet_init.EnableIPChecksumOffload = false;
    enet_init.EnableAutoStripCRCPAD = false;

    uint8_t destination_addr[6] = {0x01, 0x00, 0x5e, 0x7f, 0xff, 0xfa};

    ENET_InitMacController(BOARD_DEBUG_ENET_PORT, &enet_init);
    ENET_SetupMacAddrFilter(BOARD_DEBUG_ENET_PORT, ENET_FILTERS_DEST_ADDR | ENET_FILTERS_BOARDCAST_FILTER, ENET_ADDR_FILTER_NUM, 0u, destination_addr);
}

/* Initlization enet dma. */
void app_enet_init_dma()
{
    ENET_Init_Type enet_init;

    /* initialization dma. */
    enet_init.DmaXferPrior = ENET_DmaXferPrior_CyclicPriorRxTx1;
    enet_init.EnableAdvancedDesp = false;
    enet_init.AdressAlign = true;
    enet_init.EnableOperateOnSecondFrame = false;
    enet_init.TxFifoMode = ENET_FifoXferMode_StoreForward;
    enet_init.RxFifoMode = ENET_FifoXferMode_StoreForward;
    enet_init.MultipleProgrammableBurstLen = false;
    enet_init.TxBurstLen = ENET_DmaBurstLen_32Beat;
    enet_init.RxBurstLen = ENET_DmaBurstLen_32Beat;
    enet_init.TxThreshold = ENET_TxThreshold_64;
    enet_init.RxThreshold = ENET_RxThreshold_64;

    ENET_InitDmaController(BOARD_DEBUG_ENET_PORT, &enet_init);
    ENET_EnableDmaInterrupts(BOARD_DEBUG_ENET_PORT, ENET_INT_NORMAL | ENET_INT_RX_DONE, true);  /* Enable dma interrupt. */
    NVIC_EnableIRQ(BOARD_DEBUG_ENET_IRQn);
}

/* Set enet rx dma descriptor. */
void app_enet_rx()
{
    ENET_LinkRxDmaDesp(BOARD_DEBUG_ENET_PORT, RxDmaDespTab, &app_enet_rxbuf[0u][0u], ENET_RX_BUFLEN, ENET_RX_NUM);
    ENET_SetRxDmaDesp(BOARD_DEBUG_ENET_PORT, (uint32_t)RxDmaDespTab);  /* Set the first receive descriptor address. */
    ENET_EnableRxDma(BOARD_DEBUG_ENET_PORT, true);   /* Start dma receive. */
}

/* ENET Handler. */
void BOARD_DEBUG_ENET_Handler()
{
    if ( 0u != (ENET_GetDmaStatus(BOARD_DEBUG_ENET_PORT) & ENET_INT_RX_DONE) )
    {
        app_enet_rxcnt++;
        ENET_ClearDmaStatus(BOARD_DEBUG_ENET_PORT, ENET_INT_RX_DONE);
    }
}

/* EOF. */

