/*
  Web Server
 
 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield. 
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)
 
 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe
 
 */

#include <SPI.h>
#include <Ethernet.h>
#include <EEPROM.h>
#include "EEPROMAnything.h"
#include <avr/wdt.h>
#include <string.h>

#define EN 81
//#define SERIAL

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0x00, 0x08, 0xDC, 0xBD, 0x25, 0xFF };
//byte mac[] = {  
//  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

IPAddress ip(192,168,0,180);

IPAddress main_server(192,168,0,113);

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
EthernetServer server(80);
EthernetServer reset_server(91);
EthernetClient report;

long readTemp() { 
  // Read temperature sensor against 1.1V reference
  #if defined(__AVR_ATmega32U4__)
    ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0);
    ADCSRB = _BV(MUX5); // the MUX5 bit is in the ADCSRB register
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    ADMUX = _BV(REFS1) | _BV(MUX5) | _BV(MUX1);
  #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
    ADMUX = _BV(REFS1) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0);
  #else
    ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3);
  #endif

  delay(2); // Wait for ADMUX setting to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  uint8_t low = ADCL; // must read ADCL first - it then locks ADCH
  uint8_t high = ADCH; // unlocks both
  long result = (high << 8) | low; // combine the two

  return result;
}

float normalizeTemperature(long rawData) { 
  // replace these constants with your 2 data points
  // these are sample values that will get you in the ballpark (in degrees C)
  float temp1 = 0;
  long data1 = 274;
  float temp2 = 25.0;
  long data2 = 304;
 
  // calculate the scale factor
  float scaleFactor = (temp2 - temp1) / (data2 - data1);

  // now calculate the temperature
  float temp = scaleFactor * (rawData - data1) + temp1;

  return temp;
}

long readVcc() {
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
     ADMUX = _BV(MUX5) | _BV(MUX0) ;
  #else
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #endif  
 
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring
 
  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
  uint8_t high = ADCH; // unlocks both
 
  long result = (high<<8) | low;
 
  result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  return result-50; // Vcc in millivolts
}

float vref = 0, ftmp;
long vref2 = 0, tmp=0, htmp=5192, ctmp=5475;
unsigned long uptime, oldtime, utmp;
int w=255, itmp=0, lrep=0;
bool Fst=false,  B1st=false, B2st=false, load_sucsess=false, stopn=false, cmdreceive=false, status_update=true;
unsigned char r=0, g=0, b=0, i=0, Sst=0, j=0, z=0;
char buff[255], cmtmp[27], cmdbuff[40];
//errbuff[10];

struct settings_p
{
  bool Fst;
  long hcol, ccol;
  int w;
  unsigned char r, g, b, save_sucsess, Sst;
} settings;

void configureNetwork() {
  // Reads IP address from EEPROM as stored by `WriteNetworkSettings` sketch.
  
#define EEPROM_SIG_1_VALUE 0x55
#define EEPROM_SIG_2_VALUE 0xAA

#define EEPROM_SIG_1_OFFSET 0
#define EEPROM_SIG_2_OFFSET 1

#define EEPROM_GATEWAY_OFFSET 3
#define EEPROM_MASK_OFFSET 7
#define EEPROM_MAC_OFFSET 11
#define EEPROM_IP_OFFSET 17
  
  if ((EEPROM.read(EEPROM_SIG_1_OFFSET) == EEPROM_SIG_1_VALUE)
       && (EEPROM.read(EEPROM_SIG_2_OFFSET) == EEPROM_SIG_2_VALUE)) {
         ip = IPAddress(EEPROM.read(EEPROM_IP_OFFSET),
                        EEPROM.read(EEPROM_IP_OFFSET+1),
                        EEPROM.read(EEPROM_IP_OFFSET+2),
                        EEPROM.read(EEPROM_IP_OFFSET+3));  
       } else {
         ip = IPAddress(192,168,0,180);
       };
       
   // TODO: Handle MAC, mask & gateway also.    
}

int save_settings(bool en)
{
  settings.hcol=htmp;
  settings.ccol=ctmp;
  settings.Fst=Fst;
  settings.Sst=Sst;
  settings.r=r;
  settings.g=g;
  settings.b=b;
  settings.w=w;
  if(en==1) {
   settings.save_sucsess=EN;}
  if(en==0) {
   settings.save_sucsess=25;}
  EEPROM_writeAnything(21, settings);
}

int restore_settings()
{
  EEPROM_readAnything(21, settings);
  if(settings.save_sucsess==EN) {    
   htmp=settings.hcol;
   ctmp=settings.ccol;
   Fst=settings.Fst;
   Sst=settings.Sst;
   r=settings.r;
   g=settings.g;
   b=settings.b;
   w=settings.w;
   load_sucsess=1;
   return 0;
  }
  else
  {
    #if defined(SERIAL)
    //Serial.println("Error can't resore sittings, using default.");
    #endif
    load_sucsess=0;
    return 1;
  }
}

void BRwr(int BR) {
  w=BR;
  r = BR;
  if(BR!=0) { g = BR-20;}
  else {
  g=0; }
  if(BR!=0) { b = BR-55;}
  else {
  b=0; }
  RGBwr();
}

void RGBwr() {
  analogWrite(6, r);
  analogWrite(5, g);
  analogWrite(9, b);
}

void sst_up() {
        if(Sst==0)
        {
         BRwr(0); 
        }
        else if(Sst==1)
        {
         r=255;
         g=190;
         b=40;
         RGBwr(); 
        }
        else if(Sst==2)
        {
         BRwr(255); 
        }
//        else if(Sst==3)
//        {
//         r=0;
//         g=0;
//         b=255;
//         RGBwr(); 
//        }
//        else if(Sst==4)
//        {
//         r=0;
//         g=255;
//         b=0;
//         RGBwr(); 
//        } 
}
void autosave() {
  uptime = millis();
  if(uptime - oldtime > 1200000) {
    save_settings(1);
  }
  oldtime = uptime;
  if(i>20) {
    save_settings(1);
    i=0;
  }
  else {
   i++; 
  }
  status_update=true;
}

void setup() {
  wdt_disable();
  
  pinMode(4, OUTPUT); // SD
  digitalWrite(4, LOW);  
  restore_settings();
  
  RGBwr();
  digitalWrite(8, Fst);
  
  // start the Ethernet connection and the server:
  //Ethernet.begin(mac);
  Ethernet.begin(mac, ip);
  server.begin();
  pinMode(6, OUTPUT); // RED
  pinMode(5, OUTPUT); // GREEN
  pinMode(9, OUTPUT); // BLUE
  
  pinMode(8, OUTPUT); // UP light
  
  pinMode(7, INPUT); //BUT2 def HIGH
  pinMode(1, INPUT); //BUT1 def HIGH
  
  #if defined(SERIAL)
  //Serial.print("server is at ");
  //Serial.println(Ethernet.localIP());
  #endif
  save_settings(1);
  delay(200);
  attachInterrupt(0, hot, RISING);
  attachInterrupt(1, cold, RISING);
}

void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  EthernetClient reset_client = reset_server.available();
  
  if (reset_client) {
    reset_client.println("HTTP/1.1 200 OK");
    reset_client.println("Content-Type: text/html");
    reset_client.println("Connection: close");  
    reset_client.println();
    reset_client.println("<!DOCTYPE TEXT>");
    reset_client.println("Reset starting...");
    delay(200);
    reset_client.stop();
    save_settings(1);
    wdt_disable();  
    delay(20);
    detachInterrupt(0);
    detachInterrupt(1);
    analogWrite(5, 0);
    analogWrite(9, 0);
    digitalWrite(4, HIGH); 
    delay(1500);
    digitalWrite(4, LOW);   
    //wdt_enable(WDTO_2S);
    while (1)
    {
     analogWrite(6, 255);
     delay(500); 
     analogWrite(6, 0);
     delay(500); 
    }
  }
  stopn=false;
  if (client) {
    #if defined(SERIAL)
    //Serial.println("new client");
    #endif
    j=0;
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if(j<250) {
          buff[j]=c;
          j++;
        }
        #if defined(SERIAL)
        //Serial.write(c);
        #endif
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Content-Language: en, ru");
          client.println("Cache-Control: no-cache");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          buff[j]='\0';
          j=0;
          while(buff[j]!='\0' && j < 250 && stopn==false)
          {
            if(buff[j]=='/') {
              j++;
              if(buff[j]=='p') {
               j++;
               if(buff[j]=='r') {
                client.println();
                vref=readVcc()/1000.0;
                client.print("vcc:");
                client.print(vref);
                client.print(" temp:");
                client.print(readTemp()/1000.0);
                client.print(" vnet:");
                client.print((analogRead(1)/1023.0)*vref);
                client.print(" vtr:");
                client.print((analogRead(0)/1023.0)*vref*2);
                client.print(" cold:");
                client.print(ctmp); 
                client.print(" hot: ");
                client.print(htmp); 
                client.print(" r:");
                client.print(r);  
                client.print(" g:");
                client.print(g);  
                client.print(" b:");
                client.print(b);
                client.print(" Fsw:");
                client.print(Fst);
                client.print(" Ssw:");
                client.print(Sst);
                client.print(" losu:");
                client.print(load_sucsess);
                client.print(" up:");
                uptime = millis();
                client.print(uptime);
                client.println(';');
                stopn=true;
                break;
               }
              }
	      else if(buff[j]=='c' && stopn!=true) {
			  j++;
              if(buff[j]=='7')
			  {
			    j++;
		        if(buff[j]=='3')
			    {
                                   j++;
				   i=0;
				   client.println();
				   client.println("cmdreceived;");
				   while(buff[j]!='\0' && j < 250 && buff[j]!=';') {
					   //if(cmdreceive!=true) { 
                                           cmdbuff[i]=buff[j];
					   client.print(cmdbuff[i]); 
                                           //}
					   i++;
					   j++;
				   }
				   cmdbuff[i]=';';
				   cmdbuff[i+1]='\0';
                                   itmp=parse_cmd(cmdbuff);
                                   client.println();
                                   client.println(itmp);
                                   //client.println(errbuff);
                                   if(itmp>0)
                                   {
                                     digitalWrite(8, Fst);
                                     RGBwr();
                                   }
				   client.println();
				   client.print("r=");
				   client.print(r);
				   client.print(" g=");
				   client.print(g);
				   client.print(" b=");
				   client.print(b);
				   client.print(" Fst=");
				   client.print(Fst);
				   client.print(" Sst=");
				   client.println(Sst);
				   client.println();
                   cmdreceive=true;
				   stopn=true;
				   break;
				}
			   }
			  }
            }
            j++;
            if(stopn==true) {
             break;
            }
          }
          if(stopn==true) {
             delay(2);
             client.stop();
             break;
          }
          client.println("Refresh: 40");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          vref=readVcc()/1000.0;
          client.print("vcc: ");
          client.print(vref);
          client.println("<br />");    
          client.print("temp:");
          client.print(readTemp()/1000.0);
          client.println("<br />");    
          client.print("v3.3: ");
          client.print((analogRead(1)/1023.0)*vref);
          client.println("<br />");    
          client.print("vtr: ");
          client.print((analogRead(0)/1023.0)*vref*2);
          client.println("<br />");
          
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(":");
            client.print(sensorReading);
            client.println("<br />");       
          }
          client.print("cold: ");
          client.print(ctmp);
          client.println("<br />");    
          client.print("hot: ");
          client.print(htmp);
          client.println("<br />");    
          client.print("r: ");
          client.print(r);  
          client.print(" g: ");
          client.print(g);  
          client.print(" b: ");
          client.print(b);
          client.println("<br />");  
          
          client.print("1sw: ");
          client.print(Fst);
          client.println("<br />");    
          client.print("2sw: ");
          client.print(Sst);
          client.println("<br />");  
          client.print("load_sucsess: ");
          client.print(load_sucsess);
          client.println("<br />"); 
          client.print("uptime_millis: ");
          uptime = millis();
          client.print(uptime);
          client.println("ms<br />"); 
          client.print("uptime: ");
          client.print((uptime/1000)/3600);
          client.print("h ");
          utmp=((uptime/1000)% 3600) / 60; 
          client.print(utmp);
          client.print("m ");
          utmp=uptime/1000%60; 
          client.print(utmp);
          client.println("s<br />"); 
          client.print("last rep: "); 
          client.print(lrep); 
          client.println("<br /><br />"); 
          client.println("</html>");
          client.println(); 
          status_update=true;
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    delay(2);
    client.stop();
  }
  
      if(digitalRead(1)==LOW) {
       while(digitalRead(1)==LOW) {
          delay(100);
       }
       delay(100);
       Fst=!Fst;
       digitalWrite(8, Fst);
	   status_update=true;
      }
  
      if(digitalRead(7)==LOW) {
        delay(100);
        while(digitalRead(7)==LOW) {
          delay(100);
        }
        if(Sst<2)
        {
         Sst++; 
        }
        else
        {
         Sst=0; 
        }
        sst_up();
		status_update=true;
      }
	  
  if(status_update==true) {
	  
   client.stop();
   report.stop();
   lrep=report.connect(main_server, 82);
   if (lrep==1) {
    // send the HTTP PUT request:
    /* vref=readVcc()/1000.0;
	sprintf(buff,"GET /objects/?object=kitchen_controller&op=m&m=status_update&r=%d&g=%d&b=%d&1sw=%d&2sw=%d&vcc=%f&cold=%l&hot=%l&uptime=%l HTTP/1.1", r, g, b, Fst, Sst, vref, ctmp, htmp, millis());
	report.println(buff); */
    report.print("GET ");
	report.print("/objects/?object=kitchen_controller&op=m&m=status_update&r=");
	report.print(r);
	report.print("&g=");
	report.print(g);
	report.print("&b=");
	report.print(b);
	report.print("&1sw=");
	report.print(Fst);
	report.print("&2sw=");
	report.print(Sst);
    vref=readVcc()/1000.0;
	report.print("&vcc=");
	report.print(vref);
	report.print("&cold=");
	report.print(ctmp);
	report.print("&hot=");
	report.print(htmp);
	report.print("&uptime=");
	report.print(millis());
	report.println(" HTTP/1.1");
    report.println("Host: 192.168.0.113:82");
    report.println("User-Agent: arduino/1.0.0");
	//report.println(Ethernet.localIP());
    report.println("Connection: close");
    report.println();
	while(report.connected() && !report.available()) delay(1); //waits for data
	while (report.connected() || report.available()) { //connected or data available
    char c = report.read();
	}
	report.stop();
   }
   status_update=false;
  }
  delay(2);
}

void hot() {
 detachInterrupt(0);
 htmp++;
 delay(500);
 save_settings(1);
 attachInterrupt(0, hot, RISING);
 status_update=true;
}

void cold() {
 detachInterrupt(1);
 ctmp++;
 save_settings(1);
 delay(500);
 attachInterrupt(1, cold, RISING);
 status_update=true;
}

int parse_cmd(char *cmd) {
	int cmdcol = 0, cc = 0, cd = 0, z = 0, i = 0, j = 0;
	const char cmd_splint = '&', data_splint = ':';
	char tmpstrl[10], tmpstrd[10];
	bool stopb = false;
	i = 0;
	while (i<39 && cmd[i] != ';' && cmd[i] != '\0')
	{
		if (cmd[i] == ' ' || cmd[i] == cmd_splint) {
			cc++;
		}
		if (cmd[i] == data_splint) {
			cd++;
		}
		i++;
	}
	cc++;
	//Sireal.println(cc);
	//Sireal.println(cd);
	if (cc != cd) {
		//sprintf(errbuff, "cmd:%s", cmd);
		return -1;
	}
	if (cc <= 0) {
		return -2;
	}
	j = 0;
	i = 0;
	while (i<39 && cmd[i] != ';' && cmd[i] != '\0')
	{
		if (cmd[i] == data_splint) {
			tmpstrl[j] = '\0';
			//sprintf(errbuff, "cmd:%s", cmd);
			j = 0;
			i++;
			while (i<39 && cmd[i] != '\0') {
				if (cmd[i] == ' ' || cmd[i] == cmd_splint || cmd[i] == ';') {
					tmpstrd[j] = '\0';
					j = 0;
					//sprintf(errbuff, "tmpstrl:%s\ntmpstrd:%s", tmpstrl, tmpstrd);
					while (j <= cc) {
						if (tmpstrl[0] == 'r')
						{
							r = atoi(tmpstrd);
						}
						else if (tmpstrl[0] == 'g')
						{
							g = atoi(tmpstrd);
						}
						else if (tmpstrl[0] == 'b')
						{
							b = atoi(tmpstrd);
						}
						else if(tmpstrl[0] == 'F')
						{
							Fst=atoi(tmpstrd);
						}
						else if(tmpstrl[0] == 'S')
						{
							Sst=atoi(tmpstrd);
						    sst_up();
						}
						j++;
						i++;
						stopb = true;
						break;
					}
					if (stopb == true) {
						stopb = false;
						break;
					}
					i++;
					j = 0;
				}

				tmpstrd[j] = cmd[i];
				i++;
				j++;
			}
			//i++;
			j = 0;
		}
		tmpstrl[j] = cmd[i];
		i++;
		j++;
	}
	return cc;
}
