#include "string.h"
#include "includes.h"
#include "lwip/netif.h"
#include "arch/ethernetif.h"
#include "arch/sys_arch.h"
#include "lwip/init.h"
#include "lwip/timers.h"
#include "lwip/tcpip.h"
#include "lwip/dhcp.h"
#include "lwip/inet.h"

struct netif gnetif;
ETH_InitTypeDef ETH_InitStructure;
uint32_t  EthStatus = 0;


//初始ETH设备端口
void ETH_GPIO_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  
  /* Enable GPIOs clocks */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOE |
                         RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOG, ENABLE);

  /* Enable SYSCFG clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);  

  /* MII/RMII Media interface selection --------------------------------------*/
  SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_MII);
	
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; 	

  /* Configure PA1, PA2 and PA7 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_7;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_ETH);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_ETH);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_ETH);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_ETH);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_ETH);

  /* Configure PB5 and PB8 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_10;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_ETH);	
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_ETH);	
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_ETH);	
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_ETH);

  /* Configure PC1, PC2, PC3, PC4 and PC5 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource1, GPIO_AF_ETH);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource2, GPIO_AF_ETH);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource3, GPIO_AF_ETH);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource4, GPIO_AF_ETH);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_ETH);
                                
  /* Configure PG11, PG14 and PG13 */
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14;
  GPIO_Init(GPIOG, &GPIO_InitStructure);
  GPIO_PinAFConfig(GPIOG, GPIO_PinSource11, GPIO_AF_ETH);
  GPIO_PinAFConfig(GPIOG, GPIO_PinSource13, GPIO_AF_ETH);
  GPIO_PinAFConfig(GPIOG, GPIO_PinSource14, GPIO_AF_ETH);
}

//硬件复位PHY
void ETH_PHY_RESET(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;  
  GPIO_Init(GPIOE, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOE, GPIO_Pin_2);	
	systick_delayms(10);
	GPIO_ResetBits(GPIOE, GPIO_Pin_2);	
	systick_delayms(10);
	GPIO_SetBits(GPIOE, GPIO_Pin_2);	
	systick_delayms(10);
}


//配置以太网接收中断
void ETH_NVIC_Config(void)
{
  NVIC_InitTypeDef   NVIC_InitStructure;

  /* Enable the Ethernet global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = ETH_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);    
	
  /* Enable the Ethernet Rx Interrupt */
  ETH_DMAClearITPendingBit(ETH_DMA_IT_R);
  ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);	
  ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R, ENABLE);
}


//配置以太网外设
static void ETH_MACDMA_Config(void)
{
  ETH_InitTypeDef ETH_InitStructure;

  /* Enable ETHERNET clock  */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx |
                         RCC_AHB1Periph_ETH_MAC_Rx, ENABLE);                                             

  /* Reset ETHERNET on AHB Bus */
  ETH_DeInit();

  /* Software reset */
  ETH_SoftwareReset();

  /* Wait for software reset */
  while (ETH_GetSoftwareResetStatus() == SET);

  /* ETHERNET Configuration --------------------------------------------------*/
  /* Call ETH_StructInit if you don't like to configure all ETH_InitStructure parameter */
  ETH_StructInit(&ETH_InitStructure);

  /* Fill ETH_InitStructure parametrs */
  /*------------------------   MAC   -----------------------------------*/
  ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;
  //ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Disable; 
  //  ETH_InitStructure.ETH_Speed = ETH_Speed_10M;
  //  ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;   

  ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;
  ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;
  ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;
  ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;
  ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;
  ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;
  ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;
  ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;
#ifdef CHECKSUM_BY_HARDWARE
  ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable;
#endif

  /*------------------------   DMA   -----------------------------------*/  
  
  /* When we use the Checksum offload feature, we need to enable the Store and Forward mode: 
  the store and forward guarantee that a whole frame is stored in the FIFO, so the MAC can insert/verify the checksum, 
  if the checksum is OK the DMA can handle the frame otherwise the frame is dropped */
  ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable; 
  ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;         
  ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;     
 
  ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;       
  ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;   
  ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable;
  ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;      
  ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable;                
  ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;          
  ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;
  ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;

  /* Configure Ethernet */
	if(ETH_Init(&ETH_InitStructure, DP83848_PHY_ADDRESS)) EthStatus = ETH_INIT_FLAG;
  else                                                  EthStatus = 0;
}

//获取phy连接状态   1:连接   0:断开
uint8_t hd_ethGetPhyStatus(void)
{
	if(ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_BSR) & 0x00000004) return 1;
	else                                                               return 0;
}

void ETH_BSP_Config(void)
{
	ETH_GPIO_Config();
	ETH_PHY_RESET();
	ETH_MACDMA_Config();
	if(EthStatus & ETH_INIT_FLAG) ETH_NVIC_Config();	
	if(hd_ethGetPhyStatus()) EthStatus |= ETH_LINK_FLAG;
}


//以太网中断处理函数
extern OS_EVENT *ETH_RecvDataSem;
void ETH_IRQHandler(void)
{
  /* Frame received */
  if (ETH_GetDMAFlagStatus(ETH_DMA_FLAG_R) == SET) 
  {
		OSSemPost(ETH_RecvDataSem);
  }
	
  /* Clear the interrupt flags. */
  /* Clear the Eth DMA Rx IT pending bits */
  ETH_DMAClearITPendingBit(ETH_DMA_IT_R);
  ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);
}

///////////////////////////////////////////////////////PHY///////////////////////////////////////////////////////////////////////////
void low_level_init(struct netif *netif);
void hd_ethCheckLinkStatus(uint16_t phyAddr)
{
	uint8_t linksta = hd_ethGetPhyStatus();
	
	if(EthStatus & ETH_INIT_FLAG)
	{
		if(EthStatus & ETH_LINK_FLAG)
		{
			if(linksta == 0)
			{
				netif_set_link_down(&gnetif);
				EthStatus &= ~ETH_LINK_FLAG;
			}
		}
		else 
		{
			if(linksta != 0)
			{
				netif_set_link_up(&gnetif);
				EthStatus |= ETH_LINK_FLAG;
			}
		}
	}
	else 
	{
		if(linksta != 0)
		{
			low_level_init(&gnetif);
			netif_set_link_up(&gnetif);
#if LWIP_DHCP == 1
			dhcp_start(&gnetif);
#endif 			
		}
	}
}

void eth_link_callback(struct netif *netif)
{
	__IO uint32_t timeout = 0;
	uint32_t tmpreg,RegValue;
	
	if(netif_is_link_up(netif))
	{
		printf("network is up");
		
		if(ETH_InitStructure.ETH_AutoNegotiation != ETH_AutoNegotiation_Disable)
		{
			timeout = 0;
			ETH_WritePHYRegister(DP83848_PHY_ADDRESS, PHY_BCR, PHY_AutoNegotiation);
			do
			{
				timeout ++;
			}while(!(ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_BSR) & PHY_AutoNego_Complete) && (timeout < (uint32_t)PHY_READ_TO));
			
			RegValue = ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_SR);
			if(RegValue & PHY_DUPLEX_STATUS) ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;
			else                             ETH_InitStructure.ETH_Mode = ETH_Mode_HalfDuplex; 
			if(RegValue & PHY_SPEED_STATUS)  ETH_InitStructure.ETH_Speed = ETH_Speed_10M;
			else                             ETH_InitStructure.ETH_Speed = ETH_Speed_100M; 
			
			tmpreg = ETH->MACCR;
			tmpreg |= (uint32_t)(ETH_InitStructure.ETH_Speed | ETH_InitStructure.ETH_Mode);
			ETH->MACCR = (uint32_t)tmpreg;
			_eth_delay_(ETH_REG_WRITE_DELAY);
      tmpreg = ETH->MACCR;
      ETH->MACCR = tmpreg;
		}
		ETH_Start();
		
		netif_set_up(&gnetif);
	}
	else 
	{
		printf("network is down");		
		ETH_Stop();
		netif_set_down(&gnetif);
	}
}

void ethphycheck_timer(void *arg)
{
  LWIP_UNUSED_ARG(arg);

  hd_ethCheckLinkStatus(DP83848_PHY_ADDRESS);
  sys_timeout(1000, ethphycheck_timer, NULL);
}

///////////////////////////////////////////////////////LWIP///////////////////////////////////////////////////////////////////////////
//初始化LWIP协议栈
void lwIP_Init(void)
{
	struct ip_addr ipaddr;
	struct ip_addr netmask;
	struct ip_addr gw;
	
	tcpip_init(NULL, NULL);

#if LWIP_DHCP == 1
	ip_addr_set_zero(&ipaddr);
	ip_addr_set_zero(&netmask);	
	ip_addr_set_zero(&gw);		
#else	
//	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 

	netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ethernetif_init, tcpip_input);
	netif_set_default(&gnetif);	
	
//	netif_set_up(&gnetif);
	if(EthStatus == (ETH_LINK_FLAG | ETH_INIT_FLAG))
	{
		gnetif.flags |= NETIF_FLAG_LINK_UP; 
		netif_set_up(&gnetif);
		ETH_Start();
		
#if LWIP_DHCP == 1	
		dhcp_start(&gnetif);
		while(ip_addr_cmp(&(gnetif.ip_addr), &ipaddr))
		{
			OSTimeDly(10/(1000/OS_TICKS_PER_SEC));
		}
		printf("dhcp ip_addr is %s \r\n", inet_ntoa(gnetif.ip_addr));
#endif 		
	}
	else 
	{
		netif_set_down(&gnetif);
		gnetif.flags &= ~NETIF_FLAG_LINK_UP; 
		ETH_Stop();
	}
	
	netif_set_link_callback(&gnetif, eth_link_callback);
	sys_timeout(2000, ethphycheck_timer, NULL);
}














