text: /* ----------------------------------------------------------------------------
   * Copyright (c) Huawei Technologies Co., Ltd. 2013-2020. All rights reserved.
   * Description: Targets Stm32f429 Src Eth
   * Author: Huawei LiteOS Team
   * Create: 2013-01-01
   * Redistribution and use in source and binary forms, with or without modification,
   * are permitted provided that the following conditions are met:
   * 1. Redistributions of source code must retain the above copyright notice, this list of
   * conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright notice, this list
   * of conditions and the following disclaimer in the documentation and/or other materials
   * provided with the distribution.
   * 3. Neither the name of the copyright holder nor the names of its contributors may be used
   * to endorse or promote products derived from this software without specific prior written
   * permission.
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   * --------------------------------------------------------------------------- */
  
  #ifdef LOSCFG_COMPONENTS_NET_LWIP
  #include "eth.h"
  #include "stm32f4xx_hal.h"
  #include "stm32f4xx_hal_eth.h"
  #include "lwip/timeouts.h"
  #include "netif/etharp.h"
  #include <string.h>
  
  
  #define netifINTERFACE_TASK_STACK_SIZE              4096u
  #define netifINTERFACE_TASK_PRIORITY                6u
  /* The time to block waiting for input. */
  #define TIME_WAITING_FOR_INPUT                      500u
  
  /* Private variables ---------------------------------------------------------*/
  #if defined ( __ICCARM__ ) /*!< IAR Compiler */
  #pragma data_alignment=4
  #endif
  __ALIGN_BEGIN ETH_DMADescTypeDef  DMARxDscrTab[ETH_RXBUFNB] __ALIGN_END;/* Ethernet Rx MA Descriptor */
  
  #if defined ( __ICCARM__ ) /*!< IAR Compiler */
  #pragma data_alignment=4
  #endif
  __ALIGN_BEGIN ETH_DMADescTypeDef  DMATxDscrTab[ETH_TXBUFNB] __ALIGN_END;/* Ethernet Tx DMA Descriptor */
  
  #if defined ( __ICCARM__ ) /*!< IAR Compiler */
  #pragma data_alignment=4
  #endif
  __ALIGN_BEGIN uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __ALIGN_END; /* Ethernet Receive Buffer */
  
  #if defined ( __ICCARM__ ) /*!< IAR Compiler */
  #pragma data_alignment=4
  #endif
  __ALIGN_BEGIN uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __ALIGN_END; /* Ethernet Transmit Buffer */
  
  /* Semaphore to signal incoming packets */
  static sys_sem_t s_xSemaphore;
  /* Global Ethernet handle */
  static ETH_HandleTypeDef heth;
  
  /* Os ethernet interrupt handler */
  void ETH_IRQHandler(void)
  {
      HAL_ETH_IRQHandler(&heth);
  }
  
  /**
    * @brief  Ethernet Rx Transfer completed callback
    * @param  heth: ETH handle
    * @retval None
    */
  void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *pheth)
  {
      (void)pheth;
      sys_sem_signal(&s_xSemaphore);
  }
  
  /* Private functions ---------------------------------------------------------*/
  
  void HAL_ETH_MspInit(ETH_HandleTypeDef *ethHandle)
  {
      GPIO_InitTypeDef GPIO_InitStruct;
  
      __HAL_RCC_GPIOC_CLK_ENABLE();
      __HAL_RCC_GPIOH_CLK_ENABLE();
      __HAL_RCC_GPIOA_CLK_ENABLE();
      __HAL_RCC_GPIOB_CLK_ENABLE();
      __HAL_RCC_GPIOG_CLK_ENABLE();
      __HAL_RCC_GPIOI_CLK_ENABLE();
  
      if (ethHandle->Instance == ETH) {
          /* USER CODE BEGIN ETH_MspInit 0 */
  
          /* USER CODE END ETH_MspInit 0 */
          /* Enable Peripheral clock */
          __HAL_RCC_ETH_CLK_ENABLE();
  
          /** ETH GPIO Configuration
               PC1     ------> ETH_MDC
               PA1     ------> ETH_REF_CLK
               PA2     ------> ETH_MDIO
               PA7     ------> ETH_CRS_DV
               PC4     ------> ETH_RXD0
               PC5     ------> ETH_RXD1
               PB11     ------> ETH_TX_EN
               PG13     ------> ETH_TXD0
               PG14     ------> ETH_TXD1
               PI1      ------> ETH_NRST
               */
  
          GPIO_InitStruct.Pin = GPIO_PIN_1;
          GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
          GPIO_InitStruct.Pull = GPIO_NOPULL;
          GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
          HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
  
          HAL_GPIO_WritePin(GPIOI, GPIO_PIN_1, GPIO_PIN_RESET);
          HAL_GPIO_WritePin(GPIOI, GPIO_PIN_1, GPIO_PIN_SET);
  
          GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
          GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
          GPIO_InitStruct.Pull = GPIO_NOPULL;
          GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
          GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
          HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
  
          GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
          GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
          GPIO_InitStruct.Pull = GPIO_NOPULL;
          GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
          GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
          HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  
          GPIO_InitStruct.Pin = GPIO_PIN_11;
          GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
          GPIO_InitStruct.Pull = GPIO_NOPULL;
          GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
          GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
          HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  
          GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_14;
          GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
          GPIO_InitStruct.Pull = GPIO_NOPULL;
          GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
          GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
          HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
  
          /* Peripheral interrupt init */
          HAL_NVIC_SetPriority(ETH_IRQn, 5, 0);
          HAL_NVIC_EnableIRQ(ETH_IRQn);
          /* USER CODE BEGIN ETH_MspInit 1 */
  
          /* USER CODE END ETH_MspInit 1 */
      }
  }
  
  void HAL_ETH_MspDeInit(ETH_HandleTypeDef *ethHandle)
  {
      if (ethHandle->Instance == ETH) {
          /* USER CODE BEGIN ETH_MspDeInit 0 */
  
          /* USER CODE END ETH_MspDeInit 0 */
          /* Peripheral clock disable */
          __HAL_RCC_ETH_CLK_DISABLE();
  
          /** ETH GPIO Configuration
               PC1     ------> ETH_MDC
               PA1     ------> ETH_REF_CLK
               PA2     ------> ETH_MDIO
               PA7     ------> ETH_CRS_DV
               PC4     ------> ETH_RXD0
               PC5     ------> ETH_RXD1
               PB11     ------> ETH_TX_EN
               PG13     ------> ETH_TXD0
               PG14     ------> ETH_TXD1
               */
          HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5);
  
          HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7);
  
          HAL_GPIO_DeInit(GPIOB, GPIO_PIN_11);
          HAL_GPIO_DeInit(GPIOG, GPIO_PIN_13 | GPIO_PIN_14);
  
          /* USER CODE BEGIN ETH_MspDeInit 1 */
  
          /* USER CODE END ETH_MspDeInit 1 */
      }
  }
  
  static void eth_thread(void *arg)
  {
      while (1) {
          sys_arch_sem_wait(&s_xSemaphore, TIME_WAITING_FOR_INPUT);
          ethernetif_input(arg);
      }
  }
  
  static int8_t eth_init(struct netif *netif)
  {
      HAL_StatusTypeDef hal_eth_init_status;
  
      /* Init ETH */
      uint8_t MACAddr[6];
      heth.Instance = ETH;
      heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
      heth.Init.Speed = ETH_SPEED_100M;
      heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
      heth.Init.PhyAddress = LAN8742A_PHY_ADDRESS;
      MACAddr[0] = 0x00;
      MACAddr[1] = 0x80;
      MACAddr[2] = 0xE1;
      MACAddr[3] = 0x00;
      MACAddr[4] = 0x00;
      MACAddr[5] = 0x00;
      heth.Init.MACAddr = &MACAddr[0];
      heth.Init.RxMode = ETH_RXINTERRUPT_MODE;
  #ifdef CHECKSUM_BY_HARDWARE
      heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
  #else
      heth.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE;
  #endif
      heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
  
      hal_eth_init_status = HAL_ETH_Init(&heth);
      if (hal_eth_init_status == HAL_OK) {
          /* Set netif link flag */
          netif->flags |= NETIF_FLAG_LINK_UP;
      }
  
  #if LWIP_IPV6_MLD
      {
          /* add 33:33:xx:xx:xx:xx for ipv6 multicast */
          uint8_t ipv6_multicast_mac[6] = {0x33, 0x33, 0, 0, 0, 0};
          const uint32_t enable_bitmap = 0x30;
          (void)HAL_ETH_EnableMulticastMacAddr(&heth, ETH_MAC_ADDRESS1, ipv6_multicast_mac, enable_bitmap);
      }
  #endif
  
      /* Initialize Tx Descriptors list: Chain Mode */
      (void)HAL_ETH_DMATxDescListInit(&heth, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
  
      /* Initialize Rx Descriptors list: Chain Mode  */
      (void)HAL_ETH_DMARxDescListInit(&heth, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
  
  #if LWIP_ARP || LWIP_ETHERNET
  
      /* set MAC hardware address length */
      netif->hwaddr_len = ETH_HWADDR_LEN;
  
      /* set MAC hardware address */
      netif->hwaddr[0] =  heth.Init.MACAddr[0];
      netif->hwaddr[1] =  heth.Init.MACAddr[1];
      netif->hwaddr[2] =  heth.Init.MACAddr[2];
      netif->hwaddr[3] =  heth.Init.MACAddr[3];
      netif->hwaddr[4] =  heth.Init.MACAddr[4];
      netif->hwaddr[5] =  heth.Init.MACAddr[5];
  
      /* maximum transfer unit */
      netif->mtu = 1500;
  
      /* Accept broadcast address and ARP traffic */
      /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
  #if LWIP_ARP
      netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
  #else
      netif->flags |= NETIF_FLAG_BROADCAST;
  #endif /* LWIP_ARP */
  
  #if LWIP_IPV6_MLD
      netif->flags |= NETIF_FLAG_MLD6;
  #endif
  
  #if LWIP_IGMP
      netif->flags |= NETIF_FLAG_IGMP;
  #endif /* LWIP_IGMP */
  
      if (sys_sem_new(&s_xSemaphore, 1) != ERR_OK) {
          return -1;
      }
      /* create the task that handles the ETH_MAC */
      sys_thread_new((char *)"Eth_if", eth_thread, netif, netifINTERFACE_TASK_STACK_SIZE, netifINTERFACE_TASK_PRIORITY);
  
      /* Enable MAC and DMA transmission and reception */
      (void)HAL_ETH_Start(&heth);
  
  #endif /* LWIP_ARP || LWIP_ETHERNET */
  
      return 0;
  }
  
  static int8_t eth_output(struct netif *netif, struct pbuf *p)
  {
      err_t errval;
      struct pbuf *q = NULL;
      uint8_t *buffer = (uint8_t *)(heth.TxDesc->Buffer1Addr);
      __IO ETH_DMADescTypeDef *DmaTxDesc;
      uint32_t framelength = 0;
      uint32_t bufferoffset;
      uint32_t byteslefttocopy = 0;
      uint32_t payloadoffset = 0;
      DmaTxDesc = heth.TxDesc;
      bufferoffset = 0;
  
      /* copy frame from pbufs to driver buffers */
      for (q = p; q != NULL; q = q->next) {
          /* Is this buffer available? If not, goto error */
          if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) {
              errval = ERR_USE;
              goto error;
          }
  
          /* Get bytes in current lwIP buffer */
          byteslefttocopy = q->len;
          payloadoffset = 0;
  
          /* Check if the length of data to copy is bigger than Tx buffer size */
          while ((byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE) {
              /* Copy data to Tx buffer */
              (VOID)memcpy_s((uint8_t *)((uint8_t *)buffer + bufferoffset),
                  (ETH_TX_BUF_SIZE - bufferoffset),
                  (uint8_t *)((uint8_t *)q->payload + payloadoffset),
                  (ETH_TX_BUF_SIZE - bufferoffset));
  
              /* Point to next descriptor */
              DmaTxDesc = (ETH_DMADescTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);
  
              /* Check if the buffer is available */
              if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) {
                  errval = ERR_USE;
                  goto error;
              }
  
              buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);
  
              byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
              payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
              framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
              bufferoffset = 0;
          }
  
          /* Copy the remaining bytes */
          (VOID)memcpy_s((uint8_t *)((uint8_t *)buffer + bufferoffset),
              byteslefttocopy,
              (uint8_t *)((uint8_t *)q->payload + payloadoffset),
              byteslefttocopy);
          bufferoffset = bufferoffset + byteslefttocopy;
          framelength = framelength + byteslefttocopy;
      }
  
      /* Prepare transmit descriptors to give to DMA */
      (void)HAL_ETH_TransmitFrame(&heth, framelength);
  
      errval = ERR_OK;
  
  error:
  
      /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */
      if ((heth.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET) {
          /* Clear TUS ETHERNET DMA flag */
          heth.Instance->DMASR = ETH_DMASR_TUS;
  
          /* Resume DMA transmission */
          heth.Instance->DMATPDR = 0;
      }
  
      return errval;
  }
  
  static struct pbuf *eth_input(struct netif *netif)
  {
      struct pbuf *p = NULL;
      struct pbuf *q = NULL;
      uint16_t len;
      uint8_t *buffer = NULL;
      __IO ETH_DMADescTypeDef *dmarxdesc;
      uint32_t bufferoffset = 0;
      uint32_t payloadoffset = 0;
      uint32_t byteslefttocopy = 0;
      uint32_t i;
  
      /* get received frame */
      if (HAL_ETH_GetReceivedFrame_IT(&heth) != HAL_OK) {
          return NULL;
      }
  
      /* Obtain the size of the packet and put it into the "len" variable. */
      len = heth.RxFrameInfos.length;
      buffer = (uint8_t *)heth.RxFrameInfos.buffer;
  
      if (len > 0) {
          /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
          p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
      }
  
      if (p != NULL) {
          dmarxdesc = heth.RxFrameInfos.FSRxDesc;
          bufferoffset = 0;
  
          for (q = p; q != NULL; q = q->next) {
              byteslefttocopy = q->len;
              payloadoffset = 0;
  
              /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size */
              while ((byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE) {
                  /* Copy data to pbuf */
                  (VOID)memcpy_s((uint8_t *)((uint8_t *)q->payload + payloadoffset),
                      (ETH_RX_BUF_SIZE - bufferoffset),
                      (uint8_t *)((uint8_t *)buffer + bufferoffset),
                      (ETH_RX_BUF_SIZE - bufferoffset));
  
                  /* Point to next descriptor */
                  dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
                  buffer = (uint8_t *)(dmarxdesc->Buffer1Addr);
  
                  byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
                  payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
                  bufferoffset = 0;
              }
  
              /* Copy remaining data in pbuf */
              (VOID)memcpy_s((uint8_t *)((uint8_t *)q->payload + payloadoffset),
                  byteslefttocopy,
                  (uint8_t *)((uint8_t *)buffer + bufferoffset),
                  byteslefttocopy);
              bufferoffset = bufferoffset + byteslefttocopy;
          }
      }
  
      /* Release descriptors to DMA */
      /* Point to first descriptor */
      dmarxdesc = heth.RxFrameInfos.FSRxDesc;
  
      /* Set Own bit in Rx descriptors: gives the buffers back to DMA */
      for (i = 0; i < heth.RxFrameInfos.SegCount; i++) {
          dmarxdesc->Status |= ETH_DMARXDESC_OWN;
          dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
      }
  
      /* Clear Segment_Count */
      heth.RxFrameInfos.SegCount = 0;
  
      /* When Rx Buffer unavailable flag is set: clear it and resume reception */
      if ((heth.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET) {
          /* Clear RBUS ETHERNET DMA flag */
          heth.Instance->DMASR = ETH_DMASR_RBUS;
          /* Resume DMA reception */
          heth.Instance->DMARPDR = 0;
      }
  
      return p;
  }
  
  struct ethernet_api EthInterface(void)
  {
      struct ethernet_api ethApi = {
          .init = eth_init,
          .output = eth_output,
          .input = eth_input,
      };
      return ethApi;
  }
  #endif
  