/*------------------------------------------------------------------------------
 Copyright:      Radig Ulrich  mailto: mail@ulrichradig.de
 Author:         Radig Ulrich
 Remarks:
 known Problems: none
 Version:        24.10.2007
 Description:    Commando Interpreter

 Dieses Programm ist freie Software. Sie können es unter den Bedingungen der
 GNU General Public License, wie von der Free Software Foundation veröffentlicht,
 weitergeben und/oder modifizieren, entweder gemäß Version 2 der Lizenz oder
 (nach Ihrer Option) jeder späteren Version.

 Die Veröffentlichung dieses Programms erfolgt in der Hoffnung,
 daß es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE,
 sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT
 FÜR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License.

 Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
 Programm erhalten haben.
 Falls nicht, schreiben Sie an die Free Software Foundation,
 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#include "config.h"
#include "networkcard/enc28j60.h"
#include "networkcard/rtl8019.h"
#include "cmd.h"
#include <avr/io.h>
#include <string.h>
#include <stdlib.h>
#include <avr/eeprom.h>
#include "usart.h"
#include "stack.h"
#include "httpd.h"
#include "ntp.h"
#include "wol.h"
#include "sendmail.h"
#include "timer.h"
#include "dnsc.h"
#include "../abc/sram.h"


                        // Prototypen
void command_patch(void);               // patch SRAM
void command_dump(void);                // dump SRAM
void command_trace(void);               // set trace Bits
void command_reset     (void);          //reset the unit
void command_arp       (void);          //Ausgabe der ARP Tabelle
void command_tcp       (void);          //Ausgabe der TCP Tabelle
void command_ip        (void);          //ändern/ausgabe der IP, NETMASK, ROUTER_IP, NTP_IP
void command_net       (void);
void command_router    (void);
void command_ntp       (void);
void command_mac       (void);
void command_ver       (void);
void command_setvar    (void);

void command_ntp_refresh  (void);
#if USE_WOL
void command_wol       (void);
#endif //USE_WOL
#if USE_MAIL
void command_mail      (void);
#endif //USE_MAIL
void command_ping      (void);
void command_help      (void);
void command_sram      (void);


void write_eeprom_ip (unsigned int);
void save_ip_addresses(void);
void read_ip_addresses (void);
void sram_dump( unsigned int addr );

volatile unsigned int variable[MAX_VAR];
extern unsigned char sram_trace;           // trace flag

#if TEST_SRAM
extern volatile unsigned int timer2_event;
#endif

COMMAND_STRUCTUR COMMAND_TABELLE[] = // Befehls-Tabelle
{
   {"PATCH",command_patch},          // 20.9.11 li dazu
   {"DUMP",command_dump},            // 19.9.11 li dazu
   {"TRACE",command_trace},          // 19.9.11 li dazu
//   {"RESET",command_reset},
   {"ARP",command_arp},
   {"TCP",command_tcp},
   {"IP",command_ip},
   {"NET",command_net},
   {"ROUTER",command_router},
   {"NTP",command_ntp},
   {"MAC",command_mac},
   {"VER",command_ver},
   {"SV",command_setvar},
//   {"TIME",command_time},
   {"NTPR",command_ntp_refresh},
#if USE_WOL
   {"WOL",command_wol},
#endif //USE_WOL
   {"PING", command_ping},
   {"TSRAM",command_sram},

#if USE_MAIL
    {"mail", command_mail},
#endif //USE_MAIL
#if HELPTEXT
    {"?",command_help},
#endif //HELPTEXT
   {NULL,NULL}                // ende kennzeichen
};

#if HELPTEXT
   PROGMEM char helptext[] = {
      "PATCH  - patch von 1-8 [byt1]..\r"
      "PATCH  - patch von 10-16 [short[1]..\r"
      "DUMP   - dump von [bis]\r"
      "TRACE  - set Trace Bits\r"
//      "RESET  - reset the AVR - Controller\r"
      "ARP    - list the ARP table\r"
      "TCP    - list the tcp table\r"
      "IP     - list/change ip\r"
      "NET    - list/change netmask\r"
      "ROUTER - list/change router ip\r"
      "NTP    - list/change NTP\r"
      "NTPR   - NTP Refresh\r"
      "MAC    - list MAC-address\r"
      "VER    - list enc version number\r"
      "SV     - set variable [n] value\r"
      "PING   - send Ping\r"
      "TSRAM  - test SRAM\r"

#if USE_MAIL
      "MAIL   - send E_MAIL\r"
#endif //USE_MAIL
#if USE_WOL
      "WOL    - send WOL / set MAC / set MAC and IP\r"
#endif //USE_WOL
//      "TIME   - get time\r"
      "?      - print Helptext\r"
   };
#endif

extern S_SRAM s_sram;

/***********************************************************************
** Commando auswerten, muss ein blank am Ende haben
** genial erweiterbar
*/
unsigned char extract_cmd (char *string_pointer)
{
                                        //Stringzeiger;
   char *string_pointer_tmp;
   unsigned char cmd_index = 0;

   string_pointer_tmp = strsep( &string_pointer," ");

                                        //Kommando in Tabelle suchen
   while( strcasecmp(COMMAND_TABELLE[cmd_index].cmd, string_pointer_tmp))
   {
                                       //Abruch Whileschleife und Unterprogramm verlassen
      if (COMMAND_TABELLE[++cmd_index].cmd == 0)
         return(0);
   }

                                       //Variablen finden und auswerten
   for (unsigned char a = 0; a < MAX_VAR; a++)
   {
      string_pointer_tmp = strsep(&string_pointer,"., ");
      variable[a] = strtol(string_pointer_tmp,NULL,0);
   }

                                       //Kommando ausführen
   COMMAND_TABELLE[cmd_index].fp();

   return(1);
}




/********************************************************************
**                  Struktur
** typedef struct
** {
**  unsigned int adr;
**  unsigned char flag;  // 0b00000001 = OK
**                       // 0b00010000 = Fehler bei write loop
**                       // 0b00100000 = Fehler bei read loop
**  unsigned char soll;
**  unsigned char ist;
**  } S_SRAM;
*/
void command_sram(void)
{
#if TEST_SRAM
   timer2_event=0;
   sram_testmem( &s_sram, &timer2_event);
#else
   sram_testmem( &s_sram );
#endif
   if ( s_sram.flag == 0x01 )
   {
#if TEST_SRAM
      usart_write("sram ok, tickswrite: %i, ticksread: %i\n", s_sram.ticks_write, s_sram.ticks_read);
#else
      usart_write("sram ok\n");
#endif
   }
   else
   {
      if ( s_sram.flag == 0x10 )
         usart_write("sram test write loop error\n");

      if ( s_sram.flag == 0x20 )
         usart_write("sram test read loop error\n");
      usart_write("adresse: %04x soll:%02x ist_%02x\n", s_sram.adr, s_sram.soll, s_sram.ist);
   }
}



/**********************************************************************
** patch ab Adresse n bytes, max. 8
** 2.10.2012 bis 16 Bytes jeweils 2er Gruppen
** die Adresse und werte koennen auch hex eingegeben werden mit zB. 0x200
** variable[0] = start adresse
** variable[1] = anzahl der Bytes
** variable[2] .. die jeweiligen Bytes
*/
void command_patch(void)
{
   unsigned int adr;
   unsigned char i;

   if ( variable[1] == 0 || variable[1] > 16 )
      return;

   if ( variable[1] > 8 )   // patch in 2er Gruppen
   {
      /*
      for ( i=0; i < MAX_VAR; i++)
      {
         usart_write("VAR[%2i] %2x\r", i, variable[i] );
      }
      */
   	variable[1] /= 2;
   	adr =  variable[0];
      for ( i = 2; i < (variable[1]+2); i++)
      {
         //usart_write("s_wr %2x %1x\r", adr++, (unsigned char)(variable[i] >> 8) );
         //usart_write("s_wr %2x %1x\r", adr++, (unsigned char)(variable[i] & 0xff) );
         sram_write( adr++, (unsigned char)(variable[i] >> 8));
         sram_write( adr++, (unsigned char)variable[i] & 0xff );
      }

   }
   else
   {
      adr =  variable[0];
      for ( i = 2; i < (variable[1]+2); i++)
      {
         sram_write( adr++, (unsigned char)variable[i] );
      }
   }
}



/**********************************************************************
** dump 16 Bytes ab Adresse
** dump je 16 Bytes von Adresse bis Adresse
** die Adressen koennen auch hex eingegeben werden mit zB. 0x200
*/
void command_dump(void)
{
   unsigned int adr;

   if ( variable[1] > variable[0] )
   {
      for ( adr = variable[0]; adr < variable[1]; adr+=16)
          sram_dump( adr );
   }
   else
   {
      sram_dump( variable[0] );
   }
}



/**********************************************************************
** dump je 16 Byte
*/
void sram_dump( unsigned int addr )
{
   unsigned char i,z,p;
   char text[17];
   prog_char *atab;

   static char trtab[] PROGMEM = "................"     // 00
                                 "................"     // 10
                                 " !\"#$%&\'()*+,-./"   // 20
                                 "0123456789:;<=>?"     // 30
                                 "@ABCDEFGHIJKLMNO"     // 40
                                 "PQRSTUVWXYZ[\\]^_"    // 50
                                 "`abcdefghijklmno"     // 60
                                 "pqrstuvwxyz{|}~."     // 70
                                 "................"     // 80
                                 "................"     // 90
                                 "................"     // a0
                                 "................"     // b0
                                 "................"     // c0
                                 "................"     // d0
                                 "................"     // e0
                                 "................" ;   // f0
   atab = (prog_char*)&trtab;
   usart_write("SRAM %4x ", addr);
   p=0;
   for ( i=0; i < 16; i++)
   {
      if ( i % 4 == 0 )
         usart_write(" ");
      z = sram_read(addr++);
      text[p++] = (char)pgm_read_byte(atab+z);
      usart_write("%2x", z);
   }
   text[16]='\0';
   usart_write("   %s\r",text);
}



/**********************************************************************
** trace switch
** 30.09.2011 li
**
** .... ...1 BIT0 = trace sram_util
** .... ..1. BIT1 = trace httpd.c
** .... .1.. BIT2 = trace Soft_UART Input
** ...1 .... BIT4 = regen read / strore
** 1... .... BIT7 = clear current temperatur speicher
*/
void command_trace(void)
{
   sram_trace = (unsigned char)variable[0];
}



//------------------------------------------------------------------------------
//Reset ausführen   19.9.2011 abgeklemmt
void command_reset (void)
{
   //RESET();
}

//------------------------------------------------------------------------------
//print/edit own IP
void command_ip (void)
{
   write_eeprom_ip(IP_EEPROM_STORE);
   (*((unsigned long*)&myip[0])) = get_eeprom_value(IP_EEPROM_STORE,MYIP);
   usart_write("My IP: %1i.%1i.%1i.%1i\r",myip[0],myip[1],myip[2],myip[3]);
}


//------------------------------------------------------------------------------
//
void write_eeprom_ip (unsigned int eeprom_adresse)
{
   if (*((unsigned int*)&variable[0]) != 0x00000000)
   {
      //value ins EEPROM schreiben
      for (unsigned char count = 0; count<4;count++)
      {
         eeprom_busy_wait ();
         eeprom_write_byte((unsigned char *)(eeprom_adresse + count),variable[count]);
      }
   }
}


//------------------------------------------------------------------------------
//print/edit NTP Server IP
void command_ntp (void)
{
#if USE_NTP
   write_eeprom_ip(NTP_IP_EEPROM_STORE);
   (*((unsigned long*)&ntp_server_ip[0])) = get_eeprom_value(NTP_IP_EEPROM_STORE,NTP_IP);
   usart_write("NTP_Server: %1i.%1i.%1i.%1i\r",ntp_server_ip[0],ntp_server_ip[1],ntp_server_ip[2],ntp_server_ip[3]);
#endif //USE_NTP
}

//------------------------------------------------------------------------------
//print/edit Netmask
void command_net (void)
{
   write_eeprom_ip(NETMASK_EEPROM_STORE);
   (*((unsigned long*)&netmask[0])) = get_eeprom_value(NETMASK_EEPROM_STORE,NETMASK);
   usart_write("NETMASK: %1i.%1i.%1i.%1i\r",netmask[0],netmask[1],netmask[2],netmask[3]);
}

//------------------------------------------------------------------------------
//print/edit Router IP
void command_router (void)
{
   write_eeprom_ip(ROUTER_IP_EEPROM_STORE);
   (*((unsigned long*)&router_ip[0])) = get_eeprom_value(ROUTER_IP_EEPROM_STORE,ROUTER_IP);
   usart_write("Router IP: %1i.%1i.%1i.%1i\r",router_ip[0],router_ip[1],router_ip[2],router_ip[3]);
}

//------------------------------------------------------------------------------
//print own mac
void command_mac (void)
{
   usart_write("My MAC: %2x:%2x:%2x:%2x:%2x:%2x\r",mymac[0],mymac[1],mymac[2],mymac[3],mymac[4],mymac[5]);
}

//------------------------------------------------------------------------------
//print enc28j60 chip version
void command_ver (void)
{
#if USE_ENC28J60
   usart_write("ENC28J60-Version: %1x\r", enc28j60_revision);
#endif

#if USE_RTL8019
   usart_write("RTL8019 Ethernetcard\r");
#endif
}

//------------------------------------------------------------------------------
//print ARP table
void command_arp (void)
{
   for (unsigned char index = 0;index<MAX_ARP_ENTRY;index++)
   {
      usart_write("%2i  MAC:%2x",index,arp_entry[index].arp_t_mac[0]);
      usart_write(".%2x",arp_entry[index].arp_t_mac[1]);
      usart_write(".%2x",arp_entry[index].arp_t_mac[2]);
      usart_write(".%2x",arp_entry[index].arp_t_mac[3]);
      usart_write(".%2x",arp_entry[index].arp_t_mac[4]);
      usart_write(".%2x",arp_entry[index].arp_t_mac[5]);

      usart_write("  IP:%3i",(arp_entry[index].arp_t_ip&0x000000FF));
      usart_write(".%3i",((arp_entry[index].arp_t_ip&0x0000FF00)>>8));
      usart_write(".%3i",((arp_entry[index].arp_t_ip&0x00FF0000)>>16));
      usart_write(".%3i",((arp_entry[index].arp_t_ip&0xFF000000)>>24));

      usart_write("  Time:%4i\r",arp_entry[index].arp_t_time);
   }
}

//------------------------------------------------------------------------------
//print ARP table
void command_tcp (void)
{
   for (unsigned char index = 0;index<MAX_TCP_ENTRY;index++)
   {
      usart_write("%2i",index);
      usart_write("  IP:%3i",(tcp_entry[index].ip&0x000000FF));
      usart_write(".%3i",((tcp_entry[index].ip&0x0000FF00)>>8));
      usart_write(".%3i",((tcp_entry[index].ip&0x00FF0000)>>16));
      usart_write(".%3i",((tcp_entry[index].ip&0xFF000000)>>24));
      usart_write("  PORT:%4i",HTONS(tcp_entry[index].src_port));
      usart_write("  Time:%4i\r",tcp_entry[index].time);
   }
}

//------------------------------------------------------------------------------
//ändern einer Variable
void command_setvar (void)
{
   if ( variable[0] < MAX_VAR_ARRAY && variable[0] >= 0 )
   {
      var_array[variable[0]] = variable[1];
      usart_write("Inhalt der Variable[%2i] = %2i\r",variable[0],var_array[variable[0]]);
   }
}

//------------------------------------------------------------------------------
//print Time
void command_time (void)
{
   unsigned char hh = (time/3600)%24;
   unsigned char mm = (time/60)%60;
   unsigned char ss = time %60;
   usart_write ("TIME: %2i:%2i:%2i\r",hh,mm,ss);
}

//------------------------------------------------------------------------------
//Time Refresh via NTP-Server
void command_ntp_refresh (void)
{
   #if USE_NTP
   ntp_request();
   #endif //USE_NTP
}

//------------------------------------------------------------------------------
//Sendet eine fertige E-MAIL
#if USE_MAIL
void command_mail (void)
{
   mail_enable = 1;
}
#endif //USE_MAIL

//------------------------------------------------------------------------------
//  Wake on LAN
//
void command_wol (void)
{
#if USE_WOL
   // EEPROM beschreiben, falls Parameter angegeben wurden
   if ((*((unsigned int*)&variable[0]) != 0x00000000) || (*((unsigned int*)&variable[1]) != 0x00000000) || (*((unsigned int*)&variable[2]) != 0x00000000))
   {
      //schreiben der MAC
      for (unsigned char count = 0; count<6; count++)
      {
         eeprom_busy_wait ();
         eeprom_write_byte((unsigned char *)(WOL_MAC_EEPROM_STORE + count),variable[count]);
      }
      //zusätzlich schreiben der Broadcast-Adresse, falls vorhandenden
      for (unsigned char count = 0; count<4 && (*((unsigned int*)&variable[6]) != 0x00000000);count++)
      {
         eeprom_busy_wait ();
         eeprom_write_byte((unsigned char*)(WOL_BCAST_EEPROM_STORE + count),variable[count+6]);
      }
      //init
      wol_init();
   }else{
      //MagicPacket senden
      wol_request();
   }
#endif //USE_WOL
}

//------------------------------------------------------------------------------
// Sende "Ping" an angegebene Adresse
void command_ping (void)
{
   if (*((unsigned int*)&variable[0]) != 0x00000000)
   {
      (*((unsigned long*)&ping.ip1[0])) = ((variable[0])+((unsigned long)(variable[1])<<8)+((unsigned long)(variable[2])<<16)+((unsigned long)(variable[3])<<24));
      //ARP Request senden
      arp_request ( (*(unsigned long*)&ping.ip1[0]));

      //ICMP-Nachricht Type=8 Code=0: Echo-Anfrage
      //TODO: Sequenznummer, Identifier
      icmp_send( (*(unsigned long*)&ping.ip1[0]),0x08,0x00,1,1);
   }
}

//------------------------------------------------------------------------------
//print helptext
void command_help (void)
{
#if HELPTEXT
   unsigned char data;
   PGM_P helptest_pointer = helptext;

   do
   {
      data = pgm_read_byte(helptest_pointer++);
      if ( data != 0)
         usart_write("%c",data);
   }while(data != 0);
#endif
}

//------------------------------------------------------------------------------
//save all ip-datas
void save_ip_addresses(void)
{
   for (unsigned char count = 0; count<4; count++)
   {
      eeprom_busy_wait ();
      eeprom_write_byte((unsigned char *)(IP_EEPROM_STORE + count),myip[count]);
   }
   for (unsigned char count = 0; count<4; count++)
   {
      eeprom_busy_wait ();
      eeprom_write_byte((unsigned char *)(NETMASK_EEPROM_STORE + count),netmask[count]);
   }
   for (unsigned char count = 0; count<4; count++)
   {
      eeprom_busy_wait ();
      eeprom_write_byte((unsigned char *)(ROUTER_IP_EEPROM_STORE + count),router_ip[count]);
   }
#if USE_DNS
   for (unsigned char count = 0; count<4; count++)
   {
      eeprom_busy_wait ();
      eeprom_write_byte((unsigned char *)(DNS_IP_EEPROM_STORE + count),dns_server_ip[count]);
   }
#endif //USE_DNS
}

//------------------------------------------------------------------------------
//Read all IP-Datas
void read_ip_addresses (void)
{
  (*((unsigned long*)&myip[0]))      = get_eeprom_value(IP_EEPROM_STORE,MYIP);
  (*((unsigned long*)&netmask[0]))   = get_eeprom_value(NETMASK_EEPROM_STORE,NETMASK);
  (*((unsigned long*)&router_ip[0])) = get_eeprom_value(ROUTER_IP_EEPROM_STORE,ROUTER_IP);

#if USE_DNS
   //DNS-Server IP aus EEPROM auslesen
   (*((unsigned long*)&dns_server_ip[0])) = get_eeprom_value(DNS_IP_EEPROM_STORE,DNS_IP);
#endif
}









