/**
 * @file ethernetif.c
 * @brief CH390 Ethernet interface for lwIP NO_SYS mode.
 */

#include "lwip/opt.h"

#include "lwip/def.h"
#include "lwip/init.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/etharp.h"
#include "lwip/timeouts.h"
#include "netif/ethernet.h"
#include "ethernetif.h"

#include "CH390.h"
#include "CH390_Interface.h"
#include "ch390_runtime.h"
#include "config.h"
#include "stm32f1xx_hal.h"
#include "SEGGER_RTT.h"

#define IFNAME0 'e'
#define IFNAME1 'n'

struct netif ch390_netif;

sys_prot_t sys_arch_protect(void)
{
    __disable_irq();
    return 0u;
}

void sys_arch_unprotect(sys_prot_t pval)
{
    LWIP_UNUSED_ARG(pval);
    __enable_irq();
}

void ethernetif_set_irq_pending(void)
{
    ch390_runtime_set_irq_pending();
}

uint8_t ethernetif_is_irq_pending(void)
{
    return ch390_runtime_is_irq_pending();
}

static void low_level_init(struct netif *netif)
{
    ch390_runtime_init(netif, config_get()->net.mac);
}

static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
    return ch390_runtime_output(netif, p);
}

static struct pbuf *low_level_input(struct netif *netif)
{
    return ch390_runtime_input_frame(netif);
}

void ethernetif_input(struct netif *netif)
{
    struct pbuf *p = low_level_input(netif);

    if (p != NULL) {
        if (netif->input(p, netif) != ERR_OK) {
            pbuf_free(p);
        }
    }
}

err_t ethernetif_init(struct netif *netif)
{
    struct ethernetif *ethernetif;

    LWIP_ASSERT("netif != NULL", (netif != NULL));

    ethernetif = mem_malloc(sizeof(struct ethernetif));
    if (ethernetif == NULL) {
        return ERR_MEM;
    }

    netif->state = ethernetif;
    netif->name[0] = IFNAME0;
    netif->name[1] = IFNAME1;
#if LWIP_NETIF_HOSTNAME
    netif->hostname = "tcp2uart";
#endif
    MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 100000000);
#if LWIP_IPV4
    netif->output = etharp_output;
#endif
    netif->linkoutput = low_level_output;
    low_level_init(netif);

    return ERR_OK;
}

void lwip_netif_init(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw)
{
    netif_add(&ch390_netif, ipaddr, netmask, gw, NULL, &ethernetif_init, &ethernet_input);
    netif_set_default(&ch390_netif);
    netif_set_link_down(&ch390_netif);
    netif_set_up(&ch390_netif);
}

void ethernetif_check_link(void)
{
    ch390_runtime_check_link(&ch390_netif);
}

void ethernetif_poll(void)
{
    ch390_runtime_poll(&ch390_netif);
}

u32_t sys_now(void)
{
    return HAL_GetTick();
}

u32_t sys_jiffies(void)
{
    return HAL_GetTick();
}
