text: /**
   * @file main.c
   * @brief
   *
   * Copyright (c) 2021 Bouffalolab team
   *
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.  The
   * ASF licenses this file to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance with the
   * License.  You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
   * License for the specific language governing permissions and limitations
   * under the License.
   *
   */
  #include "bflb_platform.h"
  #include "hal_emac.h"
  #include "lwip/opt.h"
  #include "lwip/init.h"
  #include "netif/etharp.h"
  #include "lwip/netif.h"
  #include "lwip/tcpip.h"
  #if LWIP_DHCP
  #include "lwip/dhcp.h"
  #endif
  #include "ethernetif.h"
  #include "FreeRTOS.h"
  #include "task.h"
  
  #include "tcp_client.h"
  #include "tcp_server.h"
  
  // Local IP address define
  /*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */
  #define IP_ADDR0 (uint8_t)192
  #define IP_ADDR1 (uint8_t)168
  #define IP_ADDR2 (uint8_t)1
  #define IP_ADDR3 (uint8_t)221
  
  // Local NET Mask address define
  /*NETMASK*/
  #define NETMASK_ADDR0 (uint8_t)255
  #define NETMASK_ADDR1 (uint8_t)255
  #define NETMASK_ADDR2 (uint8_t)255
  #define NETMASK_ADDR3 (uint8_t)0
  
  // Local Gateway address define
  /*Gateway Address*/
  #define GW_ADDR0 (uint8_t)192
  #define GW_ADDR1 (uint8_t)168
  #define GW_ADDR2 (uint8_t)1
  #define GW_ADDR3 (uint8_t)1
  
  static uint8_t freertos_heap[4096 * 6];
  struct netif gnetif;
  static HeapRegion_t xHeapRegions[] = {
      { (uint8_t *)freertos_heap, sizeof(freertos_heap) },
      { NULL, 0 }, /* Terminates the array. */
      { NULL, 0 }  /* Terminates the array. */
  };
  
  /* For emac tx and rx,we put here to make controlling it's size easy */
  #define ETH_RXBUFNB 5
  #define ETH_TXBUFNB 5
  uint8_t ethRxBuff[ETH_RXBUFNB][ETH_RX_BUFFER_SIZE] ATTR_EALIGN(4) = { 0 }; /* Ethernet Receive Buffers */
  uint8_t ethTxBuff[ETH_TXBUFNB][ETH_TX_BUFFER_SIZE] ATTR_EALIGN(4);         /* Ethernet Transmit Buffers */
  
  void vAssertCalled(void)
  {
      uint32_t val;
  
      MSG("vAssertCalled\r\n");
      __asm volatile("csrr %0, mcause"
                     : "=r"(val));
      MSG("RA=%08x\r\n", val);
  
      while (1)
          ;
  }
  
  void vApplicationTickHook(void)
  {
      //MSG("vApplicationTickHook\r\n");
  }
  
  void vApplicationStackOverflowHook(void)
  {
      MSG("vApplicationStackOverflowHook\r\n");
  
      while (1)
          ;
  }
  
  void vApplicationMallocFailedHook(void)
  {
      MSG("vApplicationMallocFailedHook\r\n");
  
      while (1)
          ;
  }
  void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize)
  {
      /* If the buffers to be provided to the Idle task are declared inside this
      function then they must be declared static - otherwise they will be allocated on
      the stack and so not exists after this function exits. */
      static StaticTask_t xIdleTaskTCB;
      static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE];
  
      /* Pass out a pointer to the StaticTask_t structure in which the Idle task's
      state will be stored. */
      *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
  
      /* Pass out the array that will be used as the Idle task's stack. */
      *ppxIdleTaskStackBuffer = uxIdleTaskStack;
  
      /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
      Note that, as the array is necessarily of type StackType_t,
      configMINIMAL_STACK_SIZE is specified in words, not bytes. */
      *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  }
  
  /* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
  application must provide an implementation of vApplicationGetTimerTaskMemory()
  to provide the memory that is used by the Timer service task. */
  void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize)
  {
      /* If the buffers to be provided to the Timer task are declared inside this
      function then they must be declared static - otherwise they will be allocated on
      the stack and so not exists after this function exits. */
      static StaticTask_t xTimerTaskTCB;
      static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH];
  
      /* Pass out a pointer to the StaticTask_t structure in which the Timer
      task's state will be stored. */
      *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
  
      /* Pass out the array that will be used as the Timer task's stack. */
      *ppxTimerTaskStackBuffer = uxTimerTaskStack;
  
      /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
      Note that, as the array is necessarily of type StackType_t,
      configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */
      *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
  }
  
  /**
    * @brief  Setup the network interface
    * @param  None
    * @retval None
    */
  
  static void netif_config(void)
  {
      ip_addr_t ipaddr;
      ip_addr_t netmask;
      ip_addr_t gw;
  
  #if LWIP_DHCP
      ip_addr_set_zero_ip4(&ipaddr);
      ip_addr_set_zero_ip4(&netmask);
      ip_addr_set_zero_ip4(&gw);
  #else
  
      /* IP address default setting */
      IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
      IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
      IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
  
  #endif
  
      /* add the network interface */
      netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &tcpip_input);
  
      /*  Registers the default network interface */
      netif_set_default(&gnetif);
  
      ethernet_link_status_updated(&gnetif);
  
  #if LWIP_NETIF_LINK_CALLBACK
      netif_set_link_callback(&gnetif, ethernet_link_status_updated);
  #endif
  }
  
  static void emac_lwip_init()
  {
      MSG("lwip_init\r\n");
  
      /* Initialize the LwIP stack */
      tcpip_init(NULL, NULL);
  
      MSG("netif_config\r\n");
      /* Configure the Network interface */
      netif_config();
  }
  
  void emac_init_txrx_buffer(void)
  {
      emac_bd_init((uint8_t *)ethTxBuff, ETH_TXBUFNB, (uint8_t *)ethRxBuff, ETH_RXBUFNB);
  }
  
  int main(void)
  {
      bflb_platform_init(0);
  
      MSG("EMAC lwip case\n");
      cpu_global_irq_disable();
      vPortDefineHeapRegions(xHeapRegions);
  
      emac_lwip_init();
  
      MSG("[OS] Starting tcp server task...\r\n");
      tcp_server_init();
  
      // tcp_server_raw_init();
  
      // MSG("[OS] Starting tcp client task...\r\n");
      // tcp_client_init();
  
      // tcp_client_raw_init();
  
      vTaskStartScheduler();
  
      BL_CASE_SUCCESS;
      while (1) {
      }
  }
  