//*****************************************************************************
//
//
//*****************************************************************************
// COMPILER
#include <stdarg.h>
#include "string.h"
// STELARISWARE
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_nvic.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/timer.h"

#include "utils/softeeprom.h"
// PROJECT INCLUDES
#include "sniffer.h"
#include "radio/packet.h"
#include "radio/at86rf231.h"
#include "radio/spi.h"
#include "net/http_conf.h"
#include "net/ethernetwrapper.h"
#include "myutils/crc.h"
#include "myutils/packetfifo.h"
#include  "net/zep.h"
//*****************************************************************************
//
// Defines for setting up the system clock.
//
//*****************************************************************************
#define SYSTICKHZ               100
#define SYSTICKMS               (1000 / SYSTICKHZ)
#define SYSTICKUS               (1000000 / SYSTICKHZ)
#define SYSTICKNS               (1000000000 / SYSTICKHZ)


//#define CPU_XTAL 8000000
//	#define DELAY_CYCLES 3
//	#define SYSCTL_DELAY (CPU_XTAL/DELAY_CYCLES)/1000000

#define SYSCTL_DELAY 0.375

#define timerMAX_32BIT_VALUE     ( 0xffffffffUL )

//*****************************************************************************
//
// Interrupt priority definitions.  The top 3 bits of these values are
// significant with lower values indicating higher priority interrupts.
//
//*****************************************************************************
#define TIMER_INT_PRIORITY      0x00
#define TRX_INT_PRIORITY        0x40
#define SYSTICK_INT_PRIORITY    0x80
#define ETHERNET_INT_PRIORITY   0xC0

//*****************************************************************************
//
// Global variables
//
//*****************************************************************************
    unsigned long g_TimeCounter;	
//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG

#include "myutils/uartstdio.h"

void
__error__(char *pcFilename, unsigned long ulLine)
{
}
#endif

void DebugInit(void)
{
#ifdef DEBUG
	#define BAUD_RATE 460800

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
	UARTStdioInitExpClk(0,BAUD_RATE);
#endif	
}

void DebugMsg(const char *str, ...)
{
#ifdef DEBUG
    va_list vaArgP;
    va_start(vaArgP, str);
	UARTvprintf(str,vaArgP);
	va_end(vaArgP);
#endif
}

//*****************************************************************************
//
// The interrupt handler for the SysTick interrupt.
//
//*****************************************************************************
void SysTickIntHandler(void)
{
    //
    // Call the lwIP timer handler.
    //
    lwIPTimer(SYSTICKMS);
}
//*****************************************************************************

// delay in us (should be revised)
void delay(unsigned long ul)
{

    //SysCtlDelay(SYSCTL_DELAY*ul);
    SysCtlDelay((unsigned long)(ul/SYSCTL_DELAY));
        
}
//*****************************************************************************

void trx231_irq_init(void)
{
  SysCtlPeripheralEnable(TRX231_PERIPHERAL);  
  GPIODirModeSet(TRX231_PORT_BASE, TRX231_IRQ, GPIO_DIR_MODE_HW); 
  GPIOPadConfigSet(TRX231_PORT_BASE, TRX231_IRQ, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD); 
  GPIOIntTypeSet(TRX231_PORT_BASE, TRX231_IRQ, GPIO_RISING_EDGE); 
  GPIOPinIntEnable(TRX231_PORT_BASE, TRX231_IRQ); 
  IntEnable(TRX231_PORT_IRQ);
}
//*****************************************************************************

void trx231_io_init(void)
{
    SysCtlPeripheralEnable(TRX231_PERIPHERAL); 	
    GPIOPinTypeGPIOOutput(TRX231_PORT_BASE, TRX231_RST | TRX231_SLP | TRX231_SEL0);	 							
 	
	trx231_pinset_slptr(0);
 	trx231_pinset_reset(1);
 	trx231_pinset_select(1);
 	
 	SysCtlPeripheralEnable(LED_PERIPHERAL);
 	GPIOPinTypeGPIOOutput(LED_PORT_BASE, LED_GREEN);
 	
 	ledgreen_pinset(0);
}
//*****************************************************************************

void ledgreen_pinset(tBoolean val)
{
  if(val)
  	GPIOPinWrite(LED_PORT_BASE, LED_GREEN, 0xFF);
  else
    GPIOPinWrite(LED_PORT_BASE, LED_GREEN, 0x00);  	
}
//*****************************************************************************

void trx231_pinset_select(tBoolean val)
{
  if(val)
  	GPIOPinWrite(TRX231_PORT_BASE, TRX231_SEL0, 0xFF);
  else
    GPIOPinWrite(TRX231_PORT_BASE, TRX231_SEL0, 0x00);  	
}
//*****************************************************************************

void trx231_pinset_reset(tBoolean val)
{
  if(val)
  	GPIOPinWrite(TRX231_PORT_BASE, TRX231_RST, 0xFF);
  else
    GPIOPinWrite(TRX231_PORT_BASE, TRX231_RST, 0x00);  	
}
//*****************************************************************************

void trx231_pinset_slptr(tBoolean val)
{
  if(val)
  	GPIOPinWrite(TRX231_PORT_BASE, TRX231_SLP, 0xFF);
  else
    GPIOPinWrite(TRX231_PORT_BASE, TRX231_SLP, 0x00);  
}
//*****************************************************************************

void Trx231IntHandler(void) 
{   
    GPIOPinIntClear(TRX231_PORT_BASE, TRX231_IRQ);
    trx231_irq();    
}


//*****************************************************************************
 
void SetDefaultSettings(tSnifferSettings *sniffer)
{
	sniffer->state = STOPPED;

	sniffer->dhcpOn=false;
        
	sniffer->ipaddr[0]=10;
	sniffer->ipaddr[1]=10;
	sniffer->ipaddr[2]=10;
	sniffer->ipaddr[3]=2; 

	sniffer->nmask[0]=255;
	sniffer->nmask[1]=255;
	sniffer->nmask[2]=255;
	sniffer->nmask[3]=0;
	
	sniffer->gw[0]=10;
	sniffer->gw[1]=10;
	sniffer->gw[2]=10;
	sniffer->gw[3]=1;
	
	sniffer->channel = 15;
		
	sniffer->filterPanId[0] = 0;
	sniffer->filterPanId[1] = 0;
        
        sniffer->reipaddr[0]=10;
	sniffer->reipaddr[1]=10;
	sniffer->reipaddr[2]=10;
	sniffer->reipaddr[3]=1;
        
        sniffer->report=17754;
        
        sniffer->sensitivity=HIGH;
        
       // sniffer->setConfig=false;
        
        
}

//*****************************************************************************
//
// The interrupt handler for the second timer interrupt.
//
//*****************************************************************************
tBoolean Settings_init(tSnifferSettings *sniffer)
{
  
    unsigned short *ptr_sniffer=(unsigned short*)sniffer;  
    int id;
    
    tSnifferSettings sett;
          
    //
    // initialize SoftEEPROM functionality and setup EEPROM area
    //
    if (SoftEEPROMInit(SOFTEEPROM_START, SOFTEEPROM_END, SOFTEEPROM_END-SOFTEEPROM_START) != 0)
    {    	
      DebugMsg("SoftEEPROM Init failed\n");
      return false;
    
    }
    
    
    DebugMsg("tSniff=%d, div=%d\n",sizeof(tSnifferSettings),(sizeof(tSnifferSettings)/2));
    //
    // write sniffer settings to emulation EEPROM
    //
    for(id=0;id<(sizeof(tSnifferSettings)/2);id++)
    {
      if(SoftEEPROMWrite(id, ptr_sniffer[id]))
      {
         DebugMsg("SoftEEPROM write failed on %d\n",id);
         return false;
         
      }
    }  
      
        
    //
    // read sniffer settings from emulation EEPROM
    // 
    
    unsigned short data;
    tBoolean found;
    
    ptr_sniffer=(unsigned short*)&sett;
    
    for(id=0;id<(sizeof(tSnifferSettings)/2);id++)
    {
      
      
      if(SoftEEPROMRead(id, &data, &found))
      {
         DebugMsg("SoftEEPROM read failed on %d\n",id);
         return false;          
      }
      
      //if read is succesfull than check founded data
      if(found)
        ptr_sniffer[id]=data;
      else
      {
        DebugMsg("SoftEEPROM was not found on %d\n",id);
        return false;
      }
      
    } 
      
    DebugMsg("State=%d, IP=%d.%d.%d.%d\n",sett.state, sett.ipaddr[0],
             sett.ipaddr[1],sett.ipaddr[2],sett.ipaddr[3]);
    
    DebugMsg("Mask=%d.%d.%d.%d, GW=%d.%d.%d.%d\n",sett.nmask[0],
             sett.nmask[1],sett.nmask[2],sett.nmask[3],
             sett.gw[0],sett.gw[1],sett.gw[2],sett.gw[3]);
    
    DebugMsg("ReIP=%d.%d.%d.%d, RePort=%d, Ch=%d, Sens=%d\n",sett.reipaddr[0],sett.reipaddr[1],
             sett.reipaddr[2],sett.reipaddr[3],sett.report,sett.channel,sett.sensitivity);

    return true;
}
//*****************************************************************************
//
// The interrupt handler for the second timer interrupt.
//
//*****************************************************************************
void
Timer1IntHandler(void)
{
    //
    // Clear the timer interrupt.
    //
    TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);

    //
    // Update the periodic interrupt counter.
    //
    g_TimeCounter+=1;
    DebugMsg("Timer=%u\n",g_TimeCounter);
    
    
}
//*****************************************************************************
//
// The interrupt init for Timer1.
//
//*****************************************************************************
void
Timer1_init(void)
{
  
    //
    // Enable the peripherals used by this example.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);

    //
    // Configure the two 32-bit periodic timers. Handle every 1ms.
    //

    TimerConfigure(TIMER1_BASE, TIMER_CFG_32_BIT_PER);
    //TimerConfigure(TIMER1_BASE, TIMER_CFG_32_BIT_PER_UP);
     
    
    
    TimerLoadSet(TIMER1_BASE, TIMER_A, timerMAX_32BIT_VALUE);
    //TimerLoadSet(TIMER1_BASE, TIMER_A, SysCtlClockGet());
    //TimerLoadSet(TIMER1_BASE, TIMER_A, SysCtlClockGet() / NUMBER_OF_SECS); 
    
    //
    // Setup the interrupts for the timer timeouts.
    //
 
    IntEnable(INT_TIMER1A);
    TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
    //TimerIntEnable(TIMER1_BASE, TIMER_CAPA_MATCH);

    //
    // Enable the timers.
    //
    TimerEnable(TIMER1_BASE, TIMER_A);  
}

//*****************************************************************************
//*****************************************************************************

int main(void)
{
    tSnifferSettings  sniffer;

    unsigned long g_zepCounter=0;	        

    // Set the clocking to run directly from the crystal.
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ);   
    

    //
    // Configure SysTick for a periodic interrupt.
    //
    SysTickPeriodSet(SysCtlClockGet() / SYSTICKHZ);
    SysTickEnable();
    SysTickIntEnable();
   
    
    // Init Ports, Irq etc.
    DebugInit();     
       
    
    SetDefaultSettings(&sniffer);

    if(Settings_init(&sniffer)==false)
    {
      while(1);
    
    }
        
        
    DebugMsg("\nSniffer running\n");
    DebugMsg("XTAL = %d MHz\n", SysCtlClockGet());
	
  
    EthernetPeriphInit();
    
    
    Timer1_init();

    //
    // Enable processor interrupts.
    //
    IntMasterEnable();

    EthernetSetInternalMacAddr((unsigned char *)&sniffer.macaddr);
   
    //
    // Initialize the lwIP library
    //
	IpStackInit(&sniffer);

    //
    // Initialize httpd server.
    //
	HttpdInit(&sniffer);
        

	spi_init();

	init_crc_tab();
	packetFifoInit();
	
	trx231_io_init();
	trx231_irq_init();
	trx231_print_ident();
        
       
        
    //
    // Set the interrupt priorities.  We set the SysTick interrupt to a higher
    // priority than the Ethernet interrupt to ensure that the file system
    // tick is processed if SysTick occurs while the Ethernet handler is being
    // processed.  This is very likely since all the TCP/IP and HTTP work is
    // done in the context of the Ethernet interrupt.
    //
    IntPriorityGroupingSet(4);
    IntPrioritySet(INT_ETH, ETHERNET_INT_PRIORITY);
    IntPrioritySet(FAULT_SYSTICK, SYSTICK_INT_PRIORITY);
    IntPrioritySet(INT_TIMER1A, TIMER_INT_PRIORITY);
    IntPrioritySet(INT_GPIOD, TRX_INT_PRIORITY);
    

    zep_init(&g_zepCounter, &sniffer);
    
    //zep_send();
	
	// init trx
	if(trx231_init(&g_TimeCounter))
	{			
		// set trx filter
		trx231_set_filter_panid((unsigned char *)&sniffer.filterPanId);
		// set transciever to promiscuos mode
		trx231_set_promiscuos_mode();
		// set channel
		trx231_set_channel(sniffer.channel);
		trx231_get_channel();
		// set trx to active (RX_ON) state		
		if(!trx231_setstate_RX_ON())
		{
                  
                  sniffer.state=ERROR;
                  while(1)
                  {}
		}

		sniffer.state = RUNNING;
                g_TimeCounter=0;

		
          while(1)
          {
            TtrxPacket *packetPtr;
        
            packetPtr = packetFifoGet();	
            if(packetPtr != NULL)
            {
              unsigned char i;
              for(i=0;i<packetPtr->length;i++)
                DebugMsg("|%02x", packetPtr->data[i]);
                    
              DebugMsg("|\n"); 
              
              //DebugMsg("TimerGet=%u\n",TimerValueGet(TIMER1_BASE, TIMER_A));
              
              //DebugMsg("Seq=%d, Len=%d\n",g_zepCounter, packetPtr->length);
              zep_send(packetPtr);
                
              packetFifoGetDone();
            }
            
            
            
//            if(sniffer.setConfig==true)
//            {
//                   
//    
////              lwIPNetworkConfigChange((unsigned long)sniffer.ipaddr,
////                                      (unsigned long)sniffer.nmask ,
////                                      (unsigned long)sniffer.gw , IPADDR_USE_STATIC);
////                        
//              DebugMsg("Gl: IP=%u, MASK=%u, GW=%u\n",lwIPLocalIPAddrGet(),
//                       lwIPLocalNetMaskGet(),
//                       lwIPLocalGWAddrGet()); 
//              
//              sniffer.setConfig=false;              
//            }
          }
	}
        else sniffer.state=ERROR;
}

