#include <targets/LPC2000.h>
#include <targets/liblpc2000.h>
#include <ctl_api.h>
#include "uart.h"
#include "dbuffer.h"
#include "Applications.h"
#include "Drivers.h"
static unsigned char rxchar;

extern "C" unsigned long get_uart_clk(unsigned long uartn, unsigned long fosc);

dbuffer *SerialOutRS232, *SerialOutWiFi;

char zara[100000]__attribute__ ((section(".bss2")));

dbuffer SerialOutRS232_1 __attribute__ ((section(".bss2"))), SerialOutRS232_2 __attribute__ ((section(".bss2")));

dbuffer SerialOutWiFi_1 __attribute__ ((section(".bss2"))), SerialOutWiFi_2 __attribute__ ((section(".bss2")));
#define SERIAL_BUFFER_LENGTH 2000

unsigned char DataToSend[SERIAL_BUFFER_LENGTH];
int nextDataCounter;

int recvTimeOut = 15;

/*unsigned char DataToSend3[SERIAL_BUFFER_LENGTH];
int nextDataCounter3;*/

//ANSWER serialComplete = YES;
ANSWER sendComplete = YES;



static void delay(int n)
{
  volatile int i;
  for (i = 0; i < n; ++i);
}

void UART0WriteChar(unsigned char ch)
{
  while ((U0LSR & 0x20) == 0);
  U0THR = ch;
}

void UART3WriteChar(unsigned char ch)
{
  while ((U3LSR & 0x20) == 0);
  U3THR = ch;
}

unsigned char UART0ReadChar(void)
{
  while ((U0LSR & 0x01) == 0);
  return U0RBR;
}

int UART0ReadAvailable(void)
{
  return U0LSR & 0x01;
}

static void uart0ISR(void)
{
  /* Read IIR to clear interrupt and find out the cause */
  unsigned iir = U0IIR;

  /* Handle UART interrupt */
  switch ((iir >> 1) & 0x7)
    {
      case 1:
        LedOn(LED_6);
        /* THRE interrupt */
        
        if (DataToSend[nextDataCounter] == 0)
        {
          U0IER &= ~(U0IER_THRE_Interrupt_Enable_MASK);
          sendComplete = YES;
        }else if (nextDataCounter > SERIAL_BUFFER_LENGTH)
        {
          U0IER &= ~(U0IER_THRE_Interrupt_Enable_MASK);
          sendComplete = YES;
        }
        else
          U0THR = DataToSend[nextDataCounter];
        nextDataCounter++;
          
        LedOff(LED_6);
        break;
      case 2:
        LedOn(LED_5);
        /* RDA interrupt */
        if (SerialOutWiFi->top >=DBUFFER_MAX_LENGTH-1)
        {
          unsigned char data = U0RBR;
          return;
        }
        SerialOutWiFi->AddData(U0RBR);
        SerialOutWiFi->DataRdy = YES;
        SerialOutWiFi->stamp = GetTimeStamp();
        LedOff(LED_5);
        break;
      case 3:
        /* RLS interrupt */
        break;
      case 6:
        /* CTI interrupt */
        break;
   }
}

static void uart3ISR(void)
{
  /* Read IIR to clear interrupt and find out the cause */
  unsigned iir = U3IIR;

  /* Handle UART interrupt */
  switch ((iir >> 1) & 0x7)
    {
      case 1:
        LedOn(LED_6);
        /* THRE interrupt */
        if (DataToSend[nextDataCounter] == 0)
        {
          U3IER &= ~(U3IER_THRE_Interrupt_Enable_MASK);
          sendComplete = YES;
        }
        else
          U3THR = DataToSend[nextDataCounter];
        nextDataCounter++;
        LedOff(LED_6);
        break;
      case 2:
        /* RDA interrupt */
        LedOn(LED_5);
        SerialOutRS232->AddData(U3RBR);
        SerialOutRS232->DataRdy = YES;
        SerialOutRS232->stamp = GetTimeStamp();
        LedOff(LED_5);
        break;
      case 3:
        /* RLS interrupt */
        break;
      case 6:
        /* CTI interrupt */
        break;
   }
}

void UartSetRecvTimeout(int timeout)
{
  recvTimeOut = timeout;
}

ANSWER CheckSerialBuffer(OS_CONNECT com)
{

  dbuffer* SerialOut;
  switch(com)
  {
  case OS_SERIAL:
    SerialOut = SerialOutRS232;
    break;
   case OS_WIFI:
    SerialOut = SerialOutWiFi;
    break;
  default:
    return NO;
  }
  if (GetElapsedTime(SerialOut->stamp) > recvTimeOut)
  {
    return SerialOut->DataRdy;
  }
  else
    return NO;
	//return SerialOut->DataRdy;
}

int GetSerialData(OS_CONNECT com, unsigned char* buffer)
{
	dbuffer* SerialOut;
	switch(com)
	{
	case OS_SERIAL:
		if (SerialOutRS232 == &SerialOutRS232_1)
                {
                  SerialOutRS232 = &SerialOutRS232_2;
                  SerialOut = &SerialOutRS232_1;
                }
                else
                {
                  SerialOutRS232 = &SerialOutRS232_1;
                  SerialOut = &SerialOutRS232_2;
                }
		break;
	case OS_WIFI:
		if (SerialOutWiFi == &SerialOutWiFi_1)
                {
                  SerialOutWiFi = &SerialOutWiFi_2;
                  SerialOut = &SerialOutWiFi_1;
                }
                else
                {
                  SerialOutWiFi = &SerialOutWiFi_1;
                  SerialOut = &SerialOutWiFi_2;
                }
		break;
	default:
		return -1;
	}

	int i = SerialOut->GetData(buffer);
	buffer[i] = 0;
	return i;
}

unsigned char* GetSerialData(OS_CONNECT com)
{
	dbuffer* SerialOut;
	switch(com)
	{
	case OS_SERIAL:
		if (SerialOutRS232 == &SerialOutRS232_1)
                {
                  SerialOutRS232 = &SerialOutRS232_2;
                  SerialOut = &SerialOutRS232_1;
                }
                else
                {
                  SerialOutRS232 = &SerialOutRS232_1;
                  SerialOut = &SerialOutRS232_2;
                }
		break;
	case OS_WIFI:
		if (SerialOutWiFi == &SerialOutWiFi_1)
                {
                  SerialOutWiFi = &SerialOutWiFi_2;
                  SerialOut = &SerialOutWiFi_1;
                }
                else
                {
                  SerialOutWiFi = &SerialOutWiFi_1;
                  SerialOut = &SerialOutWiFi_2;
                }
		break;
	default:
		return 0;
	}

        SerialOut->top = 0;
        SerialOut->DataRdy = NO;
        return SerialOut->A;
}

int GetSerialDataCount(OS_CONNECT com)
{
    dbuffer* SerialOut;
	switch(com)
	{
	case OS_SERIAL:
		SerialOut = SerialOutRS232;
		break;
	case OS_WIFI:
		SerialOut = SerialOutWiFi;
		break;
	default:
		return -1;
	}
	return SerialOut->GetCount();
}

void ClearSerialBuffer(OS_CONNECT com)
{
    dbuffer* SerialOut;
	switch(com)
	{
	case OS_SERIAL:
		SerialOut = SerialOutRS232;
                
		break;
	case OS_WIFI:
		SerialOut = SerialOutWiFi;
		break;

	}
        SerialOut->Clear();

}

/*
ANSWER CheckSerialSendComplete(OS_CONNECT com)
{

	switch(com)
	{
	case OS_SERIAL:
		return serialComplete;
		break;
	case OS_WIFI:
		return wifiComplete;
		break;

	}
} */

ANSWER CheckSerialSendComplete(void)
{
  return sendComplete;
}

void UART0Initialize(long int baud)
{
  /* Configure UART */
  PCLKSEL0 |= (1<<PCLKSEL0_PCLK_UART0_BIT);
  unsigned int divisor = get_uart_clk(0, OSCILLATOR_CLOCK_FREQUENCY) / (16 * baud);
  U0LCR = 0x83; /* 8 bit, 1 stop bit, no parity, enable DLAB */
  U0DLL = divisor & 0xFF;
  U0DLM = (divisor >> 8) & 0xFF;

  /*U0DLM = 0;
  U0DLL = 4;
  U0FDR |= (8<<U0FDR_MULVAL_BIT)|5;*/

  
  U0LCR &= ~0x80; /* Disable DLAB */
  PINSEL0 = PINSEL0 & (~0xF0)| 0x50;
  U0FCR = 1;

  /* Setup UART RX interrupt */
  ctl_set_isr(6, 0, CTL_ISR_TRIGGER_FIXED, uart0ISR, 0);
  ctl_unmask_isr(6);
  U0IER = 1;
  SerialOutRS232 = & SerialOutRS232_2;
  SerialOutWiFi = & SerialOutWiFi_2;
  sendComplete = YES;
  LedsEnable();

}


void UART3Initialize(long int baud, char stops, SERIAL_PARITY parity)
{
  PCONP |= PCONP_PCUART3;
  /* Configure UART */
  PCLKSEL1 |= (1<<PCLKSEL1_PCLK_UART3_BIT);
  unsigned int divisor = 0;;
  //U3LCR = 0x83; /* 8 bit, 1 stop bit, no parity, enable DLAB */
  U3LCR = (parity << 3)|((stops-1)<<2)|0x83;
  switch(baud)
  {
  default:
    divisor = get_uart_clk(3, OSCILLATOR_CLOCK_FREQUENCY) / (16 * baud);
    U3DLL = divisor & 0xFF;
    U3DLM = (divisor >> 8) & 0xFF;
    break;
  }



  
  U3LCR &= ~0x80; /* Disable DLAB */
  PINSEL9 |= (3<<PINSEL9_P4_28_BIT)|(3<<PINSEL9_P4_29_BIT) ;
  U3FCR = 1;

  /* Setup UART RX interrupt */
  ctl_set_isr(29, 5, CTL_ISR_TRIGGER_FIXED, uart3ISR, 0);
  ctl_unmask_isr(29);
  U3IER = 1;
  SerialOutRS232 = & SerialOutRS232_2;
  SerialOutWiFi = & SerialOutWiFi_2;
  sendComplete = YES;
  LedsEnable();
}



int SendSerialData(OS_CONNECT com, unsigned char* buffer)
{
  strcopy(buffer,DataToSend);
  nextDataCounter = 1;
  sendComplete = NO;

  switch(com)
  {
  case OS_WIFI:
    
    UART0WriteChar(DataToSend[0]);
    U0IER |= (U0IER_THRE_Interrupt_Enable_MASK);
    
    break;
    case OS_SERIAL:
    
    UART3WriteChar(DataToSend[0]);
    U3IER |= (U3IER_THRE_Interrupt_Enable_MASK);
    break;
  }

}