////////////////////////////////////////////////////////////////////////////////
// iTelegraph v1.2 - reduced flash memory usage version 
// by Critical Velocity, 2010
// use with arduino 017
//
////////////////////////////////////////////////////////////////////////////////


#include <Ethernet.h>
#include <Dhcp.h>
#include <LiquidCrystal.h>
#include <EEPROM.h>
#include <string.h>

#define MAXINFOTYPES   5

////////////////////// eeprom addresses //////////////////////

#define EE_REMOTEIP  	1		// addresses 1-4
#define EE_REMOTEPORT	23	// 23 and 24
#define EE_LOCALPORT	6		// 6 and 7
#define EE_LOCALIP		11	// addresses 11-14
#define EE_GATEWAY	15	// addresses 15-18
#define EE_SUBNET	19		// addresses 19-22
#define EE_LOCALMAC		8
#define EE_DHCPENABLE	10

#define EE_ENABLESPKR	26	
#define EE_LOCALECHO  27
///////////////////// pin configuration //////////////////////

#define LEDPIN		8	// digital pin LED is connected to.
#define BTN1PIN	15	// the number of the pushbutton pin
#define BTN2PIN	16
#define SPKRPIN	3	// speaker hooked up to digital pin 3
#define KEYPIN		2


////// The following macros were removed from the later	versions of avr-gcc///////////////////////
#define	cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define	sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
////////////////////////////////////////////////////////////////////////////////////////////////////


///////////////////////////// ROM STRINGS ////////////////////////////////

const char intro1[] PROGMEM =  "iTelegraph v1.2";
const char intro2a[] PROGMEM = "   Critical";
const char intro2b[] PROGMEM = "   Velocity";
const char intro3a[] PROGMEM = "getting ip...";

const char stat1a[] PROGMEM = "Local IP:";
const char stat1b[] PROGMEM = "Unknown";
const char stat2a[] PROGMEM = "Connected to:";
const char stat2b[] PROGMEM = "Not Connected:";

const char stat3[] PROGMEM = "Gateway:";
const char stat4[] PROGMEM = "Subnet:";
const char stat5[] PROGMEM = "Listening Port:";
const char stat6[] PROGMEM = "Remote Port:";
const char stat7[] PROGMEM = "Connecting to";
const char stat8[] PROGMEM = "Connect Failed!";

const char menu1a[] PROGMEM = "    ";	//"IP Missing. Try";
const char menu1b[] PROGMEM = "DHCP?";
const char menu2[] PROGMEM = " 1=Y 2=N  K=Xcl";
const char menu3[] PROGMEM = "Enter Remote IP?";
const char menu4[] PROGMEM = "RemoteIP: Key=Nx";
const char menu5[] PROGMEM = "Enter Config?";
const char menu6[] PROGMEM = "Setup Menu...";

const char menu7[] PROGMEM = "Menu...";
const char menu8[] PROGMEM = "Config ";
const char menu9[] PROGMEM = "Enable ";
const char menu10[] PROGMEM = "Config Network?";

const char menu11[] PROGMEM = "Change Ports?";
const char menu12[] PROGMEM = "Speaker?";
const char menu13[] PROGMEM = "Echo?";

const char menu14[] PROGMEM = "LocalIP:";
const char menu15[] PROGMEM = " Key=Nxt";
const char menu16[] PROGMEM = "Cfg MAC Address?";
const char menu17[] PROGMEM = "MAC Address";
const char menu18[] PROGMEM = "Saved.";

const char stat9[] PROGMEM = "Error getting";
const char stat10[] PROGMEM = "IP address!";
const char stat11[] PROGMEM = "DHCP OK.";

const char blank[] PROGMEM = "";

PGM_P array[] PROGMEM = {
    intro1, 	intro2a, 	intro2b, 	intro3a,		//0-3
    stat1a, 	stat1b, 	stat2a,		stat2b,  		//4-7
    stat3, 		stat4,		stat5,		stat6, stat7, stat8,				//8-13
    menu1a, menu1b, menu2, menu3, menu4, menu5, menu6,		//14-20
    menu7, menu8, menu9, menu10,					//21-24
    menu11, menu12, menu13, 	//25-27
    menu14, menu15, menu16, menu17, menu18,  //28
    stat9, stat10, stat11, 	//33
    blank	//36
};




byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xE1 };

char mac_lastbyte = 225;//0xE1;

char dhcpenabled = 1;    // 1 = enabled, 0 = disabled.
char speakerEnabled = 1;
char localechoEnabled = 1;

boolean remoteConnected = false;
boolean ipAcquired = false;

long server_timeout = 0;
long activeclient_timeout = 0;


//LiquidCrystal(rs, rw, enable, d4, d5, d6, d7) 
LiquidCrystal lcd(19, 4, 5, 6, 7, 9, 14);
char infotype = 0;

byte local_ip[4];
byte remote_ip[4];
byte subnet_mask[] = {255, 255, 255, 0};
byte gateway[4];

unsigned int remote_port = 23;
unsigned int local_port = 23;

// telnet defaults to port 23
Server server(local_port);
Client activeClient(remote_port);

void initonce() {
  
  
  if (  (	EEPROM.read(EE_REMOTEPORT) + EEPROM.read(EE_REMOTEPORT+1) == 0	) 
  	|| (	EEPROM.read(EE_REMOTEPORT) + EEPROM.read(EE_REMOTEPORT+1) == 510 ) ) {
    // initialize eeprom
    EEPROM.write(EE_REMOTEPORT, 	23);
    EEPROM.write(EE_REMOTEPORT+1, 0);
    EEPROM.write(EE_LOCALPORT, 		23);
    EEPROM.write(EE_LOCALPORT+1, 	0);
    // default local ip to 192.168.1.110
    
    EEPROM.write(EE_LOCALIP, 192);
    EEPROM.write(EE_LOCALIP+1, 168);
    EEPROM.write(EE_LOCALIP+2, 1);
    EEPROM.write(EE_LOCALIP+3, 110);
    
    EEPROM.write(EE_GATEWAY, 192);
    EEPROM.write(EE_GATEWAY+1, 168);
    EEPROM.write(EE_GATEWAY+2, 1);
    EEPROM.write(EE_GATEWAY+3, 1);

    EEPROM.write(EE_SUBNET, 255);
    EEPROM.write(EE_SUBNET+1, 255);
    EEPROM.write(EE_SUBNET+2, 255);
    EEPROM.write(EE_SUBNET+3, 0);    

    EEPROM.write(EE_DHCPENABLE, 1);
    
  }
}


void inline load_all_from_eeprom() {
  mac_lastbyte = EEPROM.read(EE_LOCALMAC);
  mac[5] = mac_lastbyte;
  
  load_addr_from_eeprom(local_ip, EE_LOCALIP);
  local_port  = EEPROM.read(EE_LOCALPORT) + (EEPROM.read(EE_LOCALPORT+1) << 8);
  
  load_addr_from_eeprom(remote_ip, EE_REMOTEIP);
  remote_port  = EEPROM.read(EE_REMOTEPORT) + (EEPROM.read(EE_REMOTEPORT+1) << 8);
  
  load_addr_from_eeprom(gateway, EE_GATEWAY);
  load_addr_from_eeprom(subnet_mask, EE_SUBNET);
  
  dhcpenabled = EEPROM.read(EE_DHCPENABLE);
  speakerEnabled = EEPROM.read(EE_ENABLESPKR);
  localechoEnabled = EEPROM.read(EE_LOCALECHO);	
}


void load_addr_from_eeprom(byte* destaddr, unsigned char eeprom_start_addr ) {	// max eeprom addresses of 256.
	for (unsigned char k = 0; k < 4; k++) {
		destaddr[k] = EEPROM.read(eeprom_start_addr + k);
	}
}


void write_addr_to_eeprom(byte* sourceaddr, unsigned char eeprom_start_addr ) {
	for (unsigned char k = 3; k != 0; k--) {
		EEPROM.write(eeprom_start_addr + k, sourceaddr[k]);
	} 
} 

void write_port_to_eeprom(int sourceport, unsigned char eeprom_start_addr) {
	EEPROM.write(eeprom_start_addr, 		(char)sourceport );				// LSB
	EEPROM.write(eeprom_start_addr + 1, (char)(sourceport >> 8));	// MSB
}

void inline setup()
{
	initonce();
	
  lcd.begin(16, 2);
	delay400ms();

	// reset wiznet module
	DDRC = DDRC | 0x08;
	PORTC &= 0xF7;	// pull reset line low.
	delay400ms();
	PORTC |= 0x08;  // bring high.


  /////////////////////////////////////////////////////////
  
  // initialize the digital pin as an output:
/*pinMode(LEDPIN, OUTPUT);   
  pinMode(KEYPIN, INPUT);
  digitalWrite(KEYPIN, HIGH);  // enable pullup for the key.
  digitalWrite(BTN1PIN, HIGH);  // enable pullup for the key.
  digitalWrite(BTN2PIN, HIGH);  // enable pullup for the key.
*/

  
  DDRB = DDRB | 0x01;	//pinMode(LEDPIN, OUTPUT);   
  PORTD = PORTD | 0x04;	// pinMode(KEYPIN, INPUT); digitalWrite(KEYPIN, HIGH);  // enable pullup for the key.
  PORTC = PORTC | 0x02;	//digitalWrite(BTN1PIN, HIGH);  // enable pullup for the key.
  PORTC = PORTC | 0x04;	//digitalWrite(BTN2PIN, HIGH);  // enable pullup for the key.
  
  //pinMode(lcdRWPin, OUTPUT); // sent RW on LCD to write to lcd.

  
	//////////////////////// tone generator init ////////////////////
	sbi(TCCR2A, COM2B1);
	OCR2B = 0;
	sbi(DDRD, PIND3);
	

  // Print a message to the LCD.
  lcd_putsr(0);	//lcd.print("iTelegraph v1.2");

  delay400ms();
  lcd.clear();
  lcd_putsr(1);	//intro
  lcd_pos();
  lcd_putsr(2);	//intro

  delay400ms();
  delay400ms();


  load_all_from_eeprom();
  init_servers();
  
  if (dhcpenabled == 1) {
	  // get ip from dhcp.
		get_dhcp_ip();
		if (ipAcquired) {
			connect_to_server();
		}
	}   
	else {
		// manual network configuration; use existing info.
		ethernet_start_manual();	//Ethernet.begin(mac, local_ip, gateway, subnet_mask);
		server.begin();
		ipAcquired = true;
		display_current_info(0);
	}

  
}

// info types: 	0		local ip
//							1 	remote ip
//							2		gateway
//							3		subnet
//							4		listening port
//							5		remote port

const char dci_msg[] = { 4, 6, 8, 9, 10, 11};
const char dci_type[] = { 1, 1, 1, 1, 0, 0 };	// 1 = array, 0 = port
byte* dci_addr[]	= { local_ip, remote_ip, gateway, subnet_mask };
unsigned int* dci_ports[] = { &local_port, &remote_port };


void display_current_info(char infotype) {
  lcd.clear();
	
	// switch between connected and not connected
 	if ( (infotype == 1) && (remoteConnected == false) ) 
		lcd_putsr(7);
 	else
		lcd_putsr( dci_msg[infotype] );
		
  lcd_pos();
  if ( dci_type[infotype] == 1 ) {
    printArray(dci_addr[infotype], 0);
  }
  else {
  	lcd.print((*dci_ports[infotype-4]));	// dci_types 0 are > 4.
  }
}



void connect_to_server(void) {
	activeClient.stop();
	
  // connect to the server in remote_ip.
  lcd.clear();
  lcd_putsr(12);	//lcd.print("Connecting to");
  lcd_pos();
  printArray(remote_ip, 0);

  Client myclient(remote_ip, remote_port);
  if ( myclient.connect() ) {
    activeClient = myclient;
    remoteConnected = true;
		display_current_info(1);
  }
  else {
    // client connect failed.
    lcd.clear();
    lcd_putsr(13);	//lcd.print("Connect Failed!");
    remoteConnected = false;
  }
}



void menu() {
  //
  char btnval = 0;
  char mn_type = 0;
  
  lcd.clear();
  lcd_putsr(21); //  lcd.print("Menu...");
  delay400ms();

  //////////////////////// remote ip /////////////////////////

  lcd.clear();
  lcd_putsr(17);	//lcd.print("Enter Remote IP?");
  lcd_pos();
  lcd_putyn();	//lcd.print("1=Y, 2=N");
	
	btnval = get_which_button_pressed(false);
  delay400ms();

  if (btnval== 1) {
	  
	  lcd.clear();
  	lcd_putsr(18);	//lcd.print("RemoteIP: Key=Nx");
    menu_enter_address(remote_ip);
  
    write_addr_to_eeprom(remote_ip, EE_REMOTEIP);
    
    connect_to_server();
    return;
  }

  lcd.clear();
  lcd_putsr(19);	//lcd.print("Enter Config?");
  lcd_pos();
  lcd_putyn();	//lcd.print("1=Y, 2=N");

	btnval = get_which_button_pressed(false);
  delay400ms();
  
  if (btnval == 1) {
	  lcd.clear();
  	lcd_putsr(20);	//lcd.print("Setup Menu...");
  	delay400ms();
  	menu_systemconfig();
  }

  display_current_info(0);
}

unsigned char msc_msg1[] = { 23, 24, 25, 23, 23, 30 };
unsigned char msc_msg2[] = { 15, 36, 36, 26, 27, 36 };	// 1 = array, 2 = port
unsigned char msc_type[] = { 0,  1, 1, 0, 0, 1};			// type 0 for eeprom write flags, type 1 for calling another menu
char *msc_vars[] = { &dhcpenabled, NULL, NULL, &speakerEnabled, &localechoEnabled };	// only 5 elements!
unsigned char msc_vaddr[] = { EE_DHCPENABLE, NULL, NULL, EE_ENABLESPKR, EE_LOCALECHO };				// only 5 elements!


// 0: enable dhcp?
// 1: manual network cfg
// 2: port cfg
// 3: spkr cfg
// 4: local echo
// 5: mac cfg

void menu_systemconfig() {
  


  char btnval = 0;
  
  for (char a = 0; a < 6; a++) {
		lcd.clear();
		lcd_putsr2(msc_msg1[a], msc_msg2[a]);
	  lcd_pos();
		lcd_putyn();	//lcd.print("1=Y, 2=N");
		
		btnval = get_which_button_pressed(false);
		delay400ms();
		
		if (btnval == 1) {
			if (msc_type[a] == 0) {
				*msc_vars[a] = 1;
				EEPROM.write(msc_vaddr[a], 1);
				lcd_saved();
			}
			else {
				if (a == 1)
					menu_enter_manual_ipcfg ();
				else if (a==2)
				 	menu_enter_port_cfg();
				else if (a==5)
					menu_cfg_mac();
			}
		}
		else if (btnval == 2) {
			if (msc_type[a] == 0) {
				*msc_vars[a] = 0;
				EEPROM.write(msc_vaddr[a], 0);
				lcd_saved();
			}
		}
		// key pressed moves to next function.
	}  	// end for loop
	
  	
	
}

void menu_cfg_mac() {
    lcd.clear();
  	lcd_putsr(31);	//lcd.print("MAC Address:");
	  lcd.setCursor(6, 1);
  	lcd_putsr(29);	//lcd.print("Key=Done");
  	
  	unsigned char mymac = mac_lastbyte;
  	char str[6];
  	char btnval = 0;
  	
  	while ( btnval != 3 ) {
	  	
	  	if (btnval == 1) 
	  		mymac--;
	  	else if (btnval == 2) 
	  		mymac++;
	  	
	  	lcd_pos();
	  	
  		lcd.print(itoa(mymac, str, 10));
  		lcd.print("  ");
  		
  		btnval = get_which_button_pressed(true);
  	}
  	
  	mac_lastbyte = mymac;
    mac[5] = mac_lastbyte;
    EEPROM.write(EE_LOCALMAC, mac_lastbyte);
    lcd_saved();
    
    if (dhcpenabled == 1) {
			get_dhcp_ip();
    }
    else {
    	ethernet_start_manual();
    	//Ethernet.begin(mac, local_ip, gateway, subnet_mask);
    }
    server.begin();
	
}





void menu_enter_port_cfg() {

	/////////////////////// listening port ////////////////////////
	
  lcd.clear();
  lcd_putsr(10);	//lcd.print("Listening Port:");

	local_port = menu_get_int(local_port);
	write_port_to_eeprom(local_port, EE_LOCALPORT);
	lcd_saved();
	
	/////////////////////// remote port ////////////////////////
	
  lcd.clear();
  lcd_putsr(11);	//lcd.print("Remote Port:");
 
	remote_port = menu_get_int(remote_port);
	write_port_to_eeprom(remote_port, EE_REMOTEPORT);
	lcd_saved();
	
	init_servers();
}


unsigned int menu_get_int(unsigned int startvalue) {
	unsigned int myvalue;
	unsigned long prevtime;
	unsigned long curtime;
	unsigned char count = 0;

  myvalue = startvalue;
  unsigned char btn_pressed = 0;
 	prevtime = millis();
  
  while ( btn_pressed != 3 ) {

   	curtime = millis();
    
		if (curtime - prevtime < 200) {
			count++;
			if (count > 100) { 		// time to delay before speeding up
				if (btn_pressed == 1) 
					myvalue -= 200;
				else
					myvalue += 200;
				count = 100;
			}
			else if (count > 20) {
				if (btn_pressed == 1) 
					myvalue -= 20;
				else
					myvalue += 20;
			}					
			else {
				if (btn_pressed == 1) 
	  			myvalue--;
	  		else if (btn_pressed == 2)
	  			myvalue++;
  		}
  	}
  	else {
  		count = 0;
  	}


   	prevtime = curtime;

    lcd_pos();
    lcd.print(myvalue);
    //lcd.print("    ");
    lcd_putsr(14);

	  lcd.setCursor(8, 1);
//  	lcd.print("Key=Next");
	  lcd_putsr(29); //lcd.print("Key=Next");
   	
    btn_pressed = get_which_button_pressed(true);
	}
	return myvalue;

	
}


void menu_enter_manual_ipcfg (void) {

  // enter network info manually.
  lcd.clear();
  lcd_putsr2(28,29);	//lcd_putsr(28); lcd_putsr(29);	//  lcd.print("LocalIP: Key=Nxt");
  menu_enter_address(local_ip);
  write_addr_to_eeprom(local_ip, EE_LOCALIP);
  
  lcd.clear();
  lcd_putsr2(8,29);	//lcd_putsr(8);	lcd_putsr(29);	//lcd.print("Gateway: Key=Nxt");
  menu_enter_address(gateway);
  write_addr_to_eeprom(gateway, EE_GATEWAY);
  
  lcd.clear();
  lcd_putsr2(9,29);	//lcd_putsr(9);	lcd_putsr(29);	// lcd.print("Subnet: Key=Nxt");
  menu_enter_address(subnet_mask);
  write_addr_to_eeprom(subnet_mask, EE_SUBNET);


  ethernet_start_manual();
  server.begin();
  ipAcquired = true;

  

}

void menu_enter_address(byte* address) {
  // prints and modifies on line 2.
  
  byte temp_addr[4];
  
  copy_buffer(address, temp_addr);

  lcd_pos();
  printArray(temp_addr, 1);
  
  lcd.blink();
  lcd.cursor(); // turn on cursor.

  for (char p = 0; p < 4; p++) {
    lcd.setCursor(p*4+2, 1);
    char btn_pressed = 0;
    
    while ( btn_pressed != 3 ) {
      lcd_pos();

      if (btn_pressed == 1)
      	temp_addr[p] = temp_addr[p] - 1;
      else if (btn_pressed == 2) 
      	temp_addr[p] = temp_addr[p] + 1;
      	
      printArray(temp_addr, 1);
      lcd.setCursor(p*4+2, 1);
      btn_pressed = get_which_button_pressed(true);
      
    }
    // move to next digit.
    delay400ms();
  }
  
  lcd.noCursor();
  lcd.noBlink();

  // copy results back to global var.
  copy_buffer(temp_addr, address);
  lcd_pos();
  lcd_saved();
  
}


void inline loop()
{
	char rc;  // character received.
	char ktxt = '1';
	
	signed char keyVal = get_key_input();
  if (keyVal >= 0) {
  	if (keyVal == 0)
  		ktxt = '2';
	
		if (localechoEnabled == 1) {
			activateSounder(ktxt);
		}
  	
  }   
  
  // check buttons. If any are pressed, then enter menu system.
  if (get_button_input(1) != 0) {
    menu();
  }
  else if (get_button_input(2) != 0) {
    // enter menu
    infotype++;
    if (infotype > MAXINFOTYPES) {
      infotype = 0;
    }
    
    display_current_info(infotype);
    delay400ms();
  }
  
  
  if(ipAcquired)
  {

    ///////////////////////////////////////////////////////
    // 1. read what clients connected to the local server is sending. 
    // If commands are present, activate sounder.
    ///////////////////////////////////////////////////////

    // gets a client that is connected to the server.
    Client client = server.available();

    if (client.available() > 0) {
        remoteConnected = true;
        
        activateSounder(client.read());
        client.write('.'); // writing something back makes it run faster?
       	server_timeout = 0;
       
    } // end if client is avail

    server_timeout++;
    if (server_timeout > 10000000L) {
    	client.stop();
    }


  	activeclient_timeout++;
  	if (activeclient_timeout > 2000000L) {

      	if (activeClient.connected()) {
      		activeClient.write('.');
      	}


      server.write('.');
      activeclient_timeout = 0;
  	}

    
    ///////////////////////////////////////////////////////
    // 2. read what locally initiated client received.
    // If commands are present, activate sounder.
    ///////////////////////////////////////////////////////

      if (activeClient.connected()) {
        if (activeClient.available()) { // check if there are bytes to read.
          char lrc = activeClient.read();
          activateSounder(lrc);
        }
      }

    ///////////////////////////////////////////////////////
    // 3. check the local key and send commands out to 
    // folks connected to the server and the active client.
    ///////////////////////////////////////////////////////
 

	  if (keyVal >= 0) {
    	
	   	server.write(ktxt);
		  
		  if (activeClient.connected()) {
	  	  activeClient.write(ktxt);
	  	}
		  

  	} // end if keyval == 0
    
  } // end if ip is valid


}



void activateSounder(char command) {
   if (command == '1') { // 1 = turn on sounder
      sbi(PORTB, PINB0);	//digitalWrite(LEDPIN, HIGH);   // set the LED on
      if (speakerEnabled == 1) {
      	//analogWrite(SPKRPIN, 12);  
      	OCR2B = 127;
      }
    }
    else if (command == '2') {
      cbi(PORTB, PINB0);	//digitalWrite(LEDPIN, LOW);    // set the LED off
      //analogWrite(SPKRPIN, 0);  
      OCR2B = 0;
    }
}



char get_button_input(char btnNumber) {
  // returns the value of the button selected. 0 = not pressed, 1 = pressed.
  // btnNumber corresponds to the user interface buttons.

  if (btnNumber == 1) 
   return !((PINC & 0x02) >> 1);
  else if (btnNumber == 2) 
   return !((PINC & 0x04) >> 2);
  else //  (btnNumber == 3) 
   return !((PIND & 0x04) >> 2);
}



unsigned char get_which_button_pressed(boolean allowhold) {
  // blocking function - return when a button has been pressed.
  // this can wait until the button is released (allowhold = false) or return as soon as it is pressed (allowhold = true)


  for(;;) {
		for (unsigned char b = 3; b>0; b--) {
	  	if (get_button_input(b) == 1) {  // first button pressed.
				delay(120);
	      while(get_button_input(b) == 1 && (allowhold == false));  // wait till released
	      return b;
	    }
		}
  } 

}


signed char inline get_key_input() {
	
	char btn_input;
	
	static char prev_btn_input = 0;
	
  // check button input
  btn_input = ((PIND & 0x04) >> 2);//	btn_input = digitalRead(KEYPIN);

  signed char  retval = -1;   // -1 = do nothing, 0 = key is not pressed, 1 = key is pressed.
  if (btn_input != prev_btn_input) {
    // send the change in state.
    if (btn_input == 0) {
      retval = 1;
    }
    else {
      retval = 0;
    }
    prev_btn_input = btn_input;
  }
  else { // no state change in key
    retval = -1;
  }

  return retval;
}

void copy_buffer(byte* source, byte* dest) {
  // copies a 4 byte array from source to dest.
  for (unsigned char j = 0; j< 4; j++) {
    dest[j] = source[j];
  }
}



void printArray(byte* data, char pad3)
{
  // pads to 3 digits if pad is set to 1.
  // hardcoded to 4 bytes
  static char buf[4] = { 0, 0, 0, 0 };

  for(char i = 0; i < 4; i++)
  {
    if(i != 0)
      lcd.print('.');	// delimiter
    if (pad3 == 1) {
      if (data[i] < 100)
        lcd.print(' ');
      if (data[i] < 10)
        lcd.print(' ');
    }
    lcd.print(itoa(data[i], buf, 10));	// hardcode to base 10
  }
}



void get_dhcp_ip(void) {

  lcd.clear();
  //lcd.print("getting ip...");
  lcd_putsr(3);
  

  if(Dhcp.beginWithDHCP(mac))	
  {
    
    byte buffer[4];

    Dhcp.getSubnetMask(buffer);
    copy_buffer(buffer, subnet_mask);

    Dhcp.getGatewayIp(buffer);
    copy_buffer(buffer, gateway);


    Dhcp.getLocalIp(buffer);

    // copy local ip to the global variable.
    copy_buffer(buffer, local_ip);

    ipAcquired = true;
    // start listening for clients
    server.begin();
    

    lcd.clear();
    lcd_putsr(35);	//lcd.print("DHCP OK.");
    delay400ms();
  }
  else {
    //Serial.println("Unable to acquire IP address...");
    lcd.clear();
    lcd_putsr(33);	//lcd.print("Error getting");
    lcd_pos();
    lcd_putsr(34);	//lcd.print("IP address!");
    delay(3000);
    ipAcquired = false;
    local_ip[0] = 0;
    local_ip[1] = 0;
    local_ip[2] = 0;
    local_ip[3] = 0;  
  }
}


void lcd_putsr (char i) {
	static char buf[17];
	PGM_P p;

	memcpy_P(&p, &array[i], sizeof(PGM_P));
	strcpy_P(buf, p);

	lcd.print(buf);
}

void lcd_putsr2(char a, char b) {
	lcd_putsr(a);
	lcd_putsr(b);
}

void inline lcd_putyn() {
	lcd_putsr(16);
}

void inline lcd_pos() {
	lcd.setCursor(0, 1);
}


void delay400ms() {
	delay(400);
}

void lcd_saved() {
	lcd.clear();
	lcd_putsr(32);	//lcd.print("Saved.");
	delay(700);
}

void init_servers() {
	server = Server(local_port);
	activeClient = Client(remote_port);
}

void ethernet_start_manual() {
	Ethernet.begin(mac, local_ip, gateway, subnet_mask);
}
	   
