#include "Drivers.h"

#include <targets/LPC2000.h>
#include <ctl_api.h>
#include <targets/LPC2478.h>
#include "GLCD_types.h"
#include "OS_types.h"
#define EINT3_INT 17
#define I2C1_INT 19



static CTL_ISR_FN_t penISR;
static CTL_ISR_FN_t i2c1ISR;

static void touchScreenISR(void)
{
  penISR();
  EXTINT = 1<<3;
}

static void i2c1scISR(void)
{
  i2c1ISR();
  I2C1CONCLR = 0x8;
}

void ctl_enable_touch_irq(CTL_ISR_FN_t isr)
{
  unsigned long v;
  penISR = isr;

  EXTMODE |= 1<<3; /* EXT3 is edge sensitive */
  EXTPOLAR &= (~1)<<3; /* EXT3 is falling edge sensitive */
  PINSEL4 |= 1 << 26; /* Configure P2.13 for alternate function EINT0 */

  ctl_set_isr(EINT3_INT, 3, CTL_ISR_TRIGGER_FIXED, touchScreenISR, 0);
  ctl_unmask_isr(EINT3_INT);
}

void ctl_enable_i2c1_irq(CTL_ISR_FN_t isr)
{
  unsigned long v;
  i2c1ISR = isr;

  //EXTMODE |= 1<<3; /* EXT3 is edge sensitive */
  //EXTPOLAR &= (~1)<<3; /* EXT3 is falling edge sensitive */
  //PINSEL4 |= 1 << 26; /* Configure P2.13 for alternate function EINT0 */

  ctl_set_isr(I2C1_INT, 2, CTL_ISR_TRIGGER_FIXED, i2c1scISR, 0);
  ctl_unmask_isr(I2C1_INT);
}

typedef enum TI2CStatus
{
  START_SENT = 0x08,
  RESTART_SENT = 0x10,
  T_SLAW_ACK = 0x18,
  T_SLAW_NACK = 0x20,
  T_DATA_ACK = 0x28,
  T_DATA_NACK = 0x30,
  R_SLAR_ACK = 0x40,
  R_SLAR_NACK = 0x48,
  R_DATA_ACK = 0x50,
  R_DATA_NACK = 0x58,
} TI2CStatus;

#define READING 0
#define WRITING 1

char command = 0;
short recvBuffer[5];
char recvCounter = 0;
short position = 0;
char completed = 0;
char internalState = READING;
POSITION lastPosition;

ANSWER wasReleased = YES;
ANSWER hasMoved = NO;

int tolerance = TOUCHPAD_DEAD_AREA;

void SendStart(void)
{
  I2C1CONSET = I2C1CONSET_STA;
}

void SendConversionRequestX(void)
{
  internalState = WRITING;
  command = 0xC0;
  SendStart();
  
  recvCounter = 0;
  completed = 0;
}

void SendConversionRequestY(void)
{
  internalState = WRITING;
  command = 0xD0;
  SendStart();
  
  recvCounter = 0;
  completed = 0;
}

void ReadConversion(void)
{
    internalState = READING;
   SendStart();
   completed = 0;
}



void i2c1SR(void)
{

TI2CStatus i2cstate = (TI2CStatus)I2C1STAT;
  switch(i2cstate)
  {
  case START_SENT:
  I2C1CONCLR = 0x20;
  if (internalState == WRITING)
  {
    I2C1DAT = 0x90;
  }
  else
    I2C1DAT = 0x91;
  break;
  case RESTART_SENT:
  break;
  case T_SLAW_ACK:
  I2C1DAT = command;
  break;
  case T_SLAW_NACK:
  break;
  case T_DATA_ACK:
    I2C1CONSET = I2C1CONSET_STO;
    completed = 1;
  case T_DATA_NACK:
    I2C1CONSET = I2C1CONSET_STO;
    completed = 1;
  break;
  case R_SLAR_ACK:
    I2C1CONSET = I2C1CONSET_AA;
  break;
  case R_SLAR_NACK:
    I2C1CONSET = I2C1CONSET_STO;
  break;
  case R_DATA_ACK:
    I2C1CONCLR = I2C1CONCLR_AAC;
    recvBuffer[recvCounter++] = I2C1DAT;
    I2C1CONSET = 0;
  break;
  case R_DATA_NACK:
    I2C1CONSET = I2C1CONSET_STO;
    recvBuffer[1] = I2C1DAT;
    position = ((short)recvBuffer[0]<<4)|((recvBuffer[1]>>4)&0xFF);
    completed = 1;
  break;
  default:
  break;
  }
}

ANSWER hasMovedQuery(void)
{
  return hasMoved;
}

ANSWER wasReleasedQuery(void)
{
  return wasReleased;
}

void InitTouch(void)
{
  PCLKSEL1|= 0;                       //I2C1 clock should be selected by default
  PINSEL4|= 0xF<<PINSEL4_P2_14_BIT;   //Enable I2C1 pins
    I2C1SCLL = 100;
  I2C1SCLH = 100;
  ctl_enable_i2c1_irq(i2c1SR);
  I2C1CONSET = 0x40;                  //Configure as master
}
extern POSITION clickPosition;
TOUCH_STATE touchScreenState;

void DrvTouchScreen(void)
{
  switch(touchScreenState)
  {
    case TOUCH_IDLE:
    touchScreenState = TOUCH_START;
    
    break;
    case TOUCH_START:
      SendConversionRequestX();
      touchScreenState = TOUCH_READ_X;
      break;
    case TOUCH_READ_X:
    if (completed == 0)
        break;
      ReadConversion();
      touchScreenState = TOUCH_WAIT_FOR_X;
      break;
    case TOUCH_WAIT_FOR_X:
      if (completed == 0)
        break;
      
      if (position < MIN_TOUCH_X|| position > MAX_TOUCH_X)
      {
        touchScreenState = TOUCH_IDLE;
        wasReleased = YES;
        hasMoved = NO;
        break;
      }
      clickPosition.isFresh = NO;
      clickPosition.x = (position-MIN_TOUCH_X)/((MAX_TOUCH_X-MIN_TOUCH_X)/480);
      SendConversionRequestY();
      completed = 0;
      touchScreenState = TOUCH_READ_Y;
    break;
    case TOUCH_READ_Y:
    if (completed == 0)
      break;
      ReadConversion();
      touchScreenState = TOUCH_WAIT_FOR_Y;
      break;
    case TOUCH_WAIT_FOR_Y:  
      if (completed == 0)
        break;
      if (position < MIN_TOUCH_Y|| position > MAX_TOUCH_Y)
      {
        touchScreenState = TOUCH_IDLE;
        wasReleased = YES;
        hasMoved = NO;
        break;
      }
      clickPosition.y = 272-(position-MIN_TOUCH_Y)/((MAX_TOUCH_Y-MIN_TOUCH_Y)/272);
      if (GetBacklightState() == BACKLIGHT_OFF)
      {
        BacklightRequest();
        touchScreenState = TOUCH_IDLE;
        return;
      }
      if (((ABS(clickPosition.x-lastPosition.x) > tolerance) || (ABS(clickPosition.y-lastPosition.y)>tolerance))&& wasReleased == NO && lastPosition.isFresh == YES)
      {
        clickPosition.isFresh = YES;
        hasMoved = YES;
        lastPosition.x = clickPosition.x;
        lastPosition.y = clickPosition.y;
      }
      else if (wasReleased == YES)
      {
        clickPosition.isFresh = YES;
        lastPosition.x = clickPosition.x;
        lastPosition.y = clickPosition.y;
        lastPosition.isFresh = YES;
        hasMoved = NO;
        wasReleased = NO;

      }
      else
      {
        //clickPosition.isFresh = YES;
        hasMoved = NO;
      }
      touchScreenState = TOUCH_IDLE;
      
      
      BacklightRequest();
    break;

  }
}