#include "lwip_eth.h"
#include "ethernetif_eth.h"
#include "lwip/dhcp.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/netif.h"
#include "lwip/tcpip.h"
#include "lwip_init.h"
#include "stm32f4x7_phy.h"
#include <stdio.h>

#define MAX_DHCP_TRIES 4

#ifdef USE_DHCP
dhcp_state_enum dhcp_state = DHCP_START;
ip4_addr_t      ip_address = {0};
#endif /* USE_DHCP */

struct netif gnetif;

// lwip 默认IP设置
void lwip_eth_default_ip_set(__lwip_dev *lwipx)
{

    //默认远端IP为:192.168.1.100
    lwipx->remoteip[0] = 192;
    lwipx->remoteip[1] = 168;
    lwipx->remoteip[2] = 1;
    lwipx->remoteip[3] = 10;

    // MAC地址设置(高三字节固定为:2.0.0,低三字节用STM32唯一ID)
    lwipx->mac[0] = 2; //高三字节(IEEE称之为组织唯一ID,OUI)地址固定为:2.0.0
    lwipx->mac[1] = 0;
    lwipx->mac[2] = 0;
    lwipx->mac[3] = 0; //低三字节用STM32的唯一ID
    lwipx->mac[4] = 0;
    lwipx->mac[5] = 0;

    //默认本地IP为:192.168.1.30
    lwipx->ip[0] = 192;
    lwipx->ip[1] = 168;
    lwipx->ip[2] = 1;
    lwipx->ip[3] = 40;

    //默认子网掩码:255.255.255.0
    lwipx->netmask[0] = 255;
    lwipx->netmask[1] = 255;
    lwipx->netmask[2] = 255;
    lwipx->netmask[3] = 0;

    //默认网关:192.168.1.1
    lwipx->gateway[0] = 192;
    lwipx->gateway[1] = 168;
    lwipx->gateway[2] = 1;
    lwipx->gateway[3] = 1;

    lwipx->dhcpstatus = 0; //没有DHCP
}

/*!
    \brief      initializes the LwIP stack
    \param[in]  none
    \param[out] none
    \retval     none
*/
void lwip_eth_setup(void)
{
    ip4_addr_t ipaddr;
    ip4_addr_t netmask;
    ip4_addr_t gw;

    lwip_eth_default_ip_set(&ethdev); //设置默认IP等信息
    eth_init();
    /* IP address setting */
#ifdef USE_DHCP
    ipaddr.addr  = 0;
    netmask.addr = 0;
    gw.addr      = 0;
#else
    IP4_ADDR(&ipaddr, ethdev.ip[0], ethdev.ip[1], ethdev.ip[2], ethdev.ip[3]);
    IP4_ADDR(&netmask, ethdev.netmask[0], ethdev.netmask[1], ethdev.netmask[2], ethdev.netmask[3]);
    IP4_ADDR(&gw, ethdev.gateway[0], ethdev.gateway[1], ethdev.gateway[2], ethdev.gateway[3]);

#endif /* USE_DHCP */

    /* - netif_add(struct netif *netif,
                  struct ip_addr *ipaddr,
                  struct ip_addr *netmask,
                  struct ip_addr *gw,
                  void *state,
                  err_t (* init)(struct netif *netif),
                  err_t (* input)(struct pbuf *p,
                  struct netif *netif))

      将您的网络接口添加到 netif_list。
      分配结构netif，并将指向该结构的指针作为第一个参数传递。
      使用DHCP时，请提供指向已清除的ip_addr结构的指针，否则，请使用健全的数字填充它们。
      状态指针可以为NULL。

      初始化函数指针必须指向您的以太网netif接口的初始化函数。 以下代码说明了它的用法。*/
    netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_eth_init, &tcpip_input);

    printf("LwIP Registers the default network interface....\r\n");
    /* 注册默认网络接口.*/
    netif_set_default(&gnetif);

    if (EthStatus == (ETH_INIT_FLAG))
    {
        printf("LwIP Finish interface....\r\n");
        gnetif.flags |= NETIF_FLAG_LINK_UP;
        /* 配置完成网卡后启动网卡*/
        netif_set_up(&gnetif);
    }
    else
    {
        netif_set_down(&gnetif);
    }
}

#ifdef USE_DHCP
/*!
    \brief      lwip_dhcp_process_handle
    \param[in]  none
    \param[out] none
    \retval     none
*/
void dhcp_task(void *pvParameters)
{
    ip4_addr_t   ipaddr;
    ip4_addr_t   netmask;
    ip4_addr_t   gw;
    struct dhcp *dhcp_client;

    dhcp_client = netif_dhcp_data(&gnetif);

    for (;;)
    {
        switch (dhcp_state)
        {
        case DHCP_START:
            dhcp_start(&gnetif);
            ip_address.addr = 0;
            dhcp_state      = DHCP_WAIT_ADDRESS;
            break;

        case DHCP_WAIT_ADDRESS:
            /* read the new IP address */
            ip_address.addr = gnetif.ip_addr.u_addr.ip4.addr;

            if (ip_address.addr != 0)
            {
                dhcp_state = DHCP_ADDRESS_ASSIGNED;
                /* stop DHCP */
                dhcp_stop(&gnetif);

                printf("\r\nDHCP -- eval board ip address: %d.%d.%d.%d \r\n", ip4_addr1_16(&ip_address),
                       ip4_addr2_16(&ip_address), ip4_addr3_16(&ip_address), ip4_addr4_16(&ip_address));
                OSTaskSuspend(OS_PRIO_SELF);
            }
            else
            {
                /* DHCP timeout */
                if (dhcp_client->tries > MAX_DHCP_TRIES)
                {
                    dhcp_state = DHCP_TIMEOUT;
                    /* stop DHCP */
                    dhcp_stop(&gnetif);

                    /* static address used */
                    IP4_ADDR(&ipaddr, ethdev.ip[0], ethdev.ip[1], ethdev.ip[2], ethdev.ip[3]);
                    IP4_ADDR(&netmask, ethdev.netmask[0], ethdev.netmask[1], ethdev.netmask[2], ethdev.netmask[3]);
                    IP4_ADDR(&gw, ethdev.gateway[0], ethdev.gateway[1], ethdev.gateway[2], ethdev.gateway[3]);
                    netif_set_addr(&gnetif, &ipaddr, &netmask, &gw);
                    OSTaskSuspend(OS_PRIO_SELF);
                }
            }
            break;

        default:
            break;
        }
        /* wait 500 ms */
        OSTimeDlyHMSM(0, 0, 0, 500);
    }
}
#endif /* USE_DHCP */
