/******************************************************************************
* Copyright ? 2004 Altera Corporation, San Jose, California, USA.             *
* All rights reserved. All use of this software and documentation is          *
* subject to the License Agreement located at the end of this file below.     *
*******************************************************************************
* Author - PRR/JRK                                                            *
*                                                                             *
* File: network_utilities.c                                                   *
*                                                                             *
* This file contains network utilities that work in conjunction with the LWIP *
* stack to bring up a design's IP address (using DHCP if available) and MAC   *
* address.                                                                    *
*                                                                             *
* Please refer to file readme.txt for notes on this software example.         *
******************************************************************************/
#include <stdio.h> 
#include <ctype.h>
#include <string.h>
#include "alt_lwip_dev.h"
#include "alt_types.h"
#include "sys/alt_flash.h"
#include "includes.h"
#include "io.h"
#include "user.h"

// ++hychu
#include "lcd.h"
#ifdef LWIP_DEFAULT_IF
#undef LWIP_DEFAULT_IF
#define LWIP_DEFAULT_IF "DM9000A"
#endif

#ifdef ALT_DEBUG
#define	VERB(msg) printf msg
#else
#define	VERB(msg) do { } while (0)
#endif

// -- hychu

/*
 * The "adapter" storage here is declared so that when LWIP calls the 
 * get_ip_addr() routine, the adapter struct will be populated with the 
 * network device (Ethernet MAC) that LWIP is currently trying to setup an IP
 * address for. This is later used in the dhcp_timeout_task() routine to 
 * determine if DHCP was successful for the particular adapter.
 */
struct netif* adapter;

/*
 * MicroC/OS-II semaphores are used to signal when an IP address has been
 * aquired (declared in web_serer.c), and when the LCD may be opened for
 * write.
 */
 
extern OS_EVENT *attained_ip_address_sem;

/*
 * die_with_error()
 * 
 * This routine is just called when a blocking error occurs with the example
 * design. It deletes the current task.
 */
void die_with_error(char err_msg[DIE_WITH_ERROR_BUFFER])
{
  printf("\n%s\n", err_msg);
  OSTaskDel(OS_PRIO_SELF);
  
  while(1);
}

// -- johnny

/*
 * get_ip_addr()
 * 
 * This routine is called by LWIP to obtain an IP address for the specified 
 * network adapter. Like the MAC address, obtaining an IP address is very
 * system-dependant and therefore this function is exported for the developer
 * to control.
 * 
 * In our system, we are either attempting DHCP auto-negotiation of IP address,
 * or we are setting our own static IP, Gateway, and Subnet Mask addresses our
 * self. This routine is where that happens.
 */
int get_ip_addr(alt_lwip_dev* lwip_dev, struct ip_addr* ipaddr, 
                struct ip_addr* netmask, struct ip_addr* gw,
                int* use_dhcp)
{
	int ret_code = 0;
	
// ++ hychu
	int sw;
	struct netif* netif = lwip_dev->netif;
	
	sw = IORD(SWITCH_PIO_BASE, 0);
	
	if(sw & (1<<17))
	{
		char buf[32];
    char buf1[32];
		u_char ip3, ip4;
		u_char * ptr;
		
		*use_dhcp = 0;
		
		ip3 = (sw >> 12) & 0x0F;
		ip4 = ((sw >> 8) & 0x0F) + 128;
// ++ johnny
		sprintf(buf, "#192.168.%d.%d", ip3, ip4);
		LCD_Show_Text(buf);
    LCD_Line2();
    sprintf(buf1, "MAC:009000AE00%2X",netif->hwaddr[5]);
    LCD_Show_Text(buf1);
    
		VERB(("Use static IP configuration, IP = %s\n", buf));
			  
		ptr = (u_char*)ipaddr;
		*ptr++ = 192;
		*ptr++ = 168;
		*ptr++ = ip3;
		*ptr++ = ip4;
		
		ptr = (u_char*)netmask;
		*ptr++ = 0xff;
		*ptr++ = 0xff;
		*ptr++ = 0xff;
		*ptr++ = 0;

		ptr = (u_char*)gw;
		*ptr++ = 192;
		*ptr++ = 168;
		*ptr++ = ip3;
		*ptr++ = 1;
		
		return 1;
	} // of use static
// -- hychu

  if (!strcmp(lwip_dev->name, "/dev/" LWIP_DEFAULT_IF))
  {
#if LWIP_DHCP == 1
    *use_dhcp = 1;

    /*
     * If we are telling LWIP to attempt DHCP, all that is needed is to save 
     * the the LWIP device in question to a the global netif "adapter"; the 
     * DHCP timeout task will then querry this device to see whether an IP
     * address has been set.
     * 
     * If we are not attempting DHCP, static network settings are assigned here
     * and we go on our merry way.
     */
    adapter = lwip_dev->netif;

    //printf("Using DHCP to find an IP Address\n");

#else
    IP4_ADDR(ipaddr, IPADDR0,IPADDR1,IPADDR2,IPADDR3);
    IP4_ADDR(gw, GWADDR0,GWADDR1,GWADDR2,GWADDR3);
    IP4_ADDR(netmask, MSKADDR0,MSKADDR1,MSKADDR2,MSKADDR3);
    *use_dhcp = 0;

    //printf("Static IP Address is %d.%d.%d.%d\n",         ip4_addr1(ipaddr),        ip4_addr2(ipaddr),        ip4_addr3(ipaddr),        ip4_addr4(ipaddr));

#endif /* LWIP_DHCP */



    ret_code = 1;
  }

  return ret_code;
}

/*
 * dhcp_timeout_task()
 * 
 * This LWIP-called routine is responsible for checking to see whether DHCP 
 * was sucessful. Here we check to see whether a timeout (120 seconds in this
 * case) has elapsed. If so, display an error, assign a static address, and 
 * bail out. If not, continue checking for DHCP success and bail out once
 * a DHCP address assignment is complete.
 * 
 * This routine also displays the assigned IP address to the user (via STDOUT 
 * and, if equipped, LCD screen.
 * 
 */
#if LWIP_DHCP == 1
void dhcp_timeout_task()
{
  int have_address = 0, timeout_dhcp = 0;
  struct ip_addr ipaddr, netmask, gw;
  INT8U return_code = OS_NO_ERR;

  OSSemPend(attained_ip_address_sem, 0, &return_code);

  while(1)
  {
    OSTimeDlyHMSM(0,0,0,100);

    /* 
     * For demo purposes we need to use DHCP to allocate an IP Address
     * and LWIP had no mechanism to tell us one is allocated. Wait two 
     * minutes if we don't have one we use a static IP address
     */
    if((timeout_dhcp < DHCP_TIMEOUT) && (have_address == 0))
    {
      timeout_dhcp++;
      if (!ip_addr_isany(&adapter->ip_addr))
      {
        have_address = 1;
// ++hychu
        VERB(("Assigned IP Address is %d.%d.%d.%d\n\n",                ip4_addr1(&adapter->ip_addr),                ip4_addr2(&adapter->ip_addr),                ip4_addr3(&adapter->ip_addr),                ip4_addr4(&adapter->ip_addr)));
        VERB(("Assigned GW Address is %d.%d.%d.%d\n\n",                ip4_addr1(&adapter->gw),                ip4_addr2(&adapter->gw),                ip4_addr3(&adapter->gw),                ip4_addr4(&adapter->gw)));
        {
			char buf[32];  
			sprintf(buf, "#%d.%d.%d.%d",
				ip4_addr1(&adapter->ip_addr),    
				ip4_addr2(&adapter->ip_addr),     
				ip4_addr3(&adapter->ip_addr),  
				ip4_addr4(&adapter->ip_addr)
        );
        LCD_Show_Text(buf);
        LCD_Line2();
// ++ johnny
      sprintf(buf, "MAC:009000AE00%2X",  
        adapter->hwaddr[5]    
        );
        LCD_Show_Text(buf);
        }
      }
    }
    /*
     * You're in a bit of trouble if this happens, you could assign a static
     * IP address but how do we choose it?
     */
    if (timeout_dhcp ==  DHCP_TIMEOUT)
    {
      dhcp_stop(adapter);
      IP4_ADDR(&ipaddr, IPADDR0,IPADDR1,IPADDR2,IPADDR3);
      IP4_ADDR(&gw, GWADDR0,GWADDR1,GWADDR2,GWADDR3);
      IP4_ADDR(&netmask, MSKADDR0,MSKADDR1,MSKADDR2,MSKADDR3);
      
      netif_set_addr( adapter,&ipaddr, &netmask, &gw);
      netif_set_up(adapter);
      
      //printf("DHCP Failed to assign an IP Address\n\n"); 
      //printf("\nUsing static address: %d.%d.%d.%d\n\n\n",        ip4_addr1(&adapter->ip_addr),        ip4_addr2(&adapter->ip_addr),        ip4_addr3(&adapter->ip_addr),        ip4_addr4(&adapter->ip_addr));

      have_address = 1;
    }
    
    if (have_address == 1)
    {
      /* 
       * We have an IP address this task has served it's purpose - kill it.
       */
       OSSemPost(attained_ip_address_sem);
       OSTaskDel(OS_PRIO_SELF);
    }
  }
}
#endif /* LWIP_DHCP */

/******************************************************************************
*                                                                             *
* License Agreement                                                           *
*                                                                             *
* Copyright (c) 2004 Altera Corporation, San Jose, California, USA.           *
* All rights reserved.                                                        *
*                                                                             *
* Permission is hereby granted, free of charge, to any person obtaining a     *
* copy of this software and associated documentation files (the "Software"),  *
* to deal in the Software without restriction, including without limitation   *
* the rights to use, copy, modify, merge, publish, distribute, sublicense,    *
* and/or sell copies of the Software, and to permit persons to whom the       *
* Software is furnished to do so, subject to the following conditions:        *
*                                                                             *
* The above copyright notice and this permission notice shall be included in  *
* all copies or substantial portions of the Software.                         *
*                                                                             *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     *
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         *
* DEALINGS IN THE SOFTWARE.                                                   *
*                                                                             *
* This agreement shall be governed in all respects by the laws of the State   *
* of California and by the laws of the United States of America.              *
* Altera does not recommend, suggest or require that this reference design    *
* file be used in conjunction or combination with any other product.          *
******************************************************************************/
