#include <avr/io.h>
#include <stdlib.h>
#include <string.h>
#include <avr/pgmspace.h>
#include "ip_arp_icmp.c"
#include "enc28j60.h"
#include "enc28j60.c"
#include "avr_compat.h"
#include "net.h"
#include <util/delay.h>
static uint8_t mymac[6] = {0x66,0x32,0x54,0x10,0x45,0x31};//MAC-адрес
static uint8_t myip[4] = {192,168,1,25};//IP-адрес
static char baseurl[]="http://192.168.1.25/";//значение URL
#define BUFFER_SIZE 700// размер буфера для приема данных
static uint8_t buf[BUFFER_SIZE+1];
static char password[]="secret"; //пароль(не длиннее 9 символов)
uint8_t verify_password(char *str)//функция проверки пароля (первых 5 символов)
{
  if (strncmp(password,str,5)==0)
   {
    return(1);//при совпадении возвращает 1
   }
  return(0);//при не совпадении возвращает 0
}

int8_t analyse_get_url(char *str)// функция анализа получаемого URL
{
 uint8_t i=0;
 if (verify_password(str)==0)
  {
   return(-1);//возвращает -1, если пароль не правильный
  }
 while(*str && i<10 && *str >',' && *str<'{')//если пароль правильный, найдем положение символа '/'после пароля
 {
   if (*str=='/')
    {
     str++;
     break;
    }
   i++;
   str++;
 }
 if (*str < 0x3a && *str > 0x2f)// если после '/' находится число от 0 до 9 (код ASCII)
  {
   return(*str-0x30);//возвратим значение этого числа числа в прямом виде
  }
 return(-2);// если пароль верный, но нет команды после него, то возвращает -2
}
uint16_t print_webpage(uint8_t *buf,uint8_t on_off)// записывает в буфер страницу для отправки
{
        uint16_t plen;
        plen=fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));
		plen=fill_tcp_data_p(buf,plen,PSTR("<center><font size=25>УПРАВЛЕНИЕ И МОНИТОРИНГ СОСТОЯНИЯ СВЕТОДИОДА"));
        plen=fill_tcp_data_p(buf,plen,PSTR("<center><p><font color=\"#ff0000\">Диод:</font> "));
        if (on_off)
		 {
          plen=fill_tcp_data_p(buf,plen,PSTR("<font color=\"#00FF00\"> Включен</font>"));
         }
		else
		{
         plen=fill_tcp_data_p(buf,plen,PSTR("Выключен"));
        }
        plen=fill_tcp_data_p(buf,plen,PSTR(" <small><a href=\""));
        plen=fill_tcp_data(buf,plen,baseurl);
        plen=fill_tcp_data(buf,plen,password);
        plen=fill_tcp_data_p(buf,plen,PSTR("\">[Проверить состояние]</a></small></p>\n<p><a href=\""));
        plen=fill_tcp_data(buf,plen,baseurl);
        plen=fill_tcp_data(buf,plen,password);
        if (on_off)
		 {
          plen=fill_tcp_data_p(buf,plen,PSTR("/0\">Выключить</a><p>"));
         }
		else
		 {
          plen=fill_tcp_data_p(buf,plen,PSTR("/1\">Включить</a><p>"));
         }
        plen=fill_tcp_data_p(buf,plen,PSTR("</center><br><hr>Демонстрация работы платы "));
		plen=fill_tcp_data_p(buf,plen,PSTR(" как Web-сервера. "));
		plen=fill_tcp_data_p(buf,plen,PSTR(" КубГУ.ФТФ. 2012 "));
        return(plen);
}

int main(void)
 {

    uint16_t plen;
    uint16_t dat_p;
    int8_t cmd;
    PORTD=0x00;
    DDRD=0xff;
    CLKPR=(1<<CLKPCE);//разрешаем установку частоты тактирования
    CLKPR=0; // устанавливаем частоту тактирования 8 Мгц
    _delay_ms(10);    
    enc28j60Init(mymac);//инициализация ENC28J60
    _delay_ms(20);
    enc28j60PhyWrite(PHLCON,0x476);//устанавливаем один диод для статуса соединения,другой для статуса приема/передачи
    _delay_ms(20);
    init_ip_arp(mymac,myip);//инициализация ip- и MAC-адресов

  while(1)
   {
                
   plen = enc28j60PacketReceive(BUFFER_SIZE, buf);//запускаем функцию приема пакетов от ENC28J60
   if(plen==0)// если принятых данных нет 
	{
     continue;//то перейти на начало цикла while
    }
 if(eth_type_is_arp_and_my_ip(buf,plen))// если полученные данные ARP-запрос,адресованный нам
	{       
     make_arp_answer_from_request(buf);//то сгенерировать и отправить ARP-ответ 
     continue;// перейти на начало цикла while
    }
 if(eth_type_is_ip_and_my_ip(buf,plen)==0)// если полученные данные являются ip-пакетом и адресованы не нам
	{
     continue;// перейти на начало цикла while
    }
 if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V)//если в полученном ip-пакете содержится запрос "пинг"
    {
    make_echo_reply_from_request(buf,plen);// отправим ответ "понг"
    continue;//перейти на начало цикла while
    }
 if (buf[IP_PROTO_P]==IP_PROTO_TCP_V&&buf[TCP_DST_PORT_H_P]==0&&buf[TCP_DST_PORT_L_P]==80)// если полученные данные-TCP сегменты и адресованы нам (на порт 80)
    {
     if (buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V)//если идет запрос на синхронизацию
	  {
       make_tcp_synack_from_syn(buf);//отправим подтверждение синхронизации
       continue;//выйдем из цикла и начнем принимать данные заново
      }
     if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V)//если установлен флаг подтверждения
	  {
        init_len_info(buf); //определяем длину данных в TCP сегменте
        dat_p=get_tcp_data_pointer();//устанавливаем указатель на начало данных в TCP сегменте
        if (dat_p==0)//прислан TCP сегмент без указания размера заголовка
		 {
          if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V)//если флаг завершения соединения FIN установлен
		   {
            make_tcp_ack_from_any(buf);//подтвердить завершение
           }
          continue;//и выйти из цикла
         }
        if (strncmp("GET ",(char *)&(buf[dat_p]),4)!=0)// если получен запрос "Get"
		 {
          plen=fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>200 OK</h1>"));//отправить команду 200 OK
          goto SENDTCP;//перейти к отправке
         }
        if (strncmp("/ ",(char *)&(buf[dat_p+4]),2)==0)// если получен '/ '
		 {
          plen=fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));//отправить команду 200 OK
          plen=fill_tcp_data_p(buf,plen,PSTR("<p>Usage: "));// отправить подсказку ввести пароль: "Usage:http://192.168.1.25/password
          plen=fill_tcp_data(buf,plen,baseurl);
          plen=fill_tcp_data_p(buf,plen,PSTR("password</p>"));
          goto SENDTCP;// перейти к отправке
         }
        cmd=analyse_get_url((char *)&(buf[dat_p+5]));//запускаем функцию анализа URL и записываем возвращаемое ею значение в cmd
        if (cmd==-1)// если пароль не верный
		 {
          plen=fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 401 Unauthorized\r\nContent-Type: text/html\r\n\r\n<h1>401 Unauthorized</h1>"));//оправить команду отказано в авторизации
          goto SENDTCP;//перейти к отправке
         }
        if (cmd==1)//если команда равна 1
		 {
          PORTD|= (1<<PD7);//включить светодиод PD7
         }
        if (cmd==0)//если команда равна 0
		 {
          PORTD &= ~(1<<PD7);//выключить светодиод
         }
        plen=print_webpage(buf,(PORTD & (1<<PD7)));//создать страницу 
                                
SENDTCP:
        
		make_tcp_ack_from_any(buf); // подтвердить запрос get
        make_tcp_ack_with_data(buf,plen); // отправить данные 
        continue;//выйти из цикла и перейти к началу приема данных
     }

    }
                
   }
 return (0);
}