#include "lisoc_test.h"
#include "interrupt_test.h"
#include "uart.h"
#include "timer.h"
#include "gpio.h"
#include "qspi.h"
#include "flash.h"
#include "spi.h"

#define uart_str_length 16
uint16_t tx_count = 0;
uint16_t rx_count = 0;
char str_tx[uart_str_length] = "hello world";
char str_rx[uart_str_length];
uint32_t irq_triggered = 0; /* Detected interrupt operation from IRQ handler */
uint32_t int_tmo;
#define INT_TIMEOUT 1000

uint32_t gpioa_irq_flag;
uint32_t gpiob_irq_flag;
uint32_t qspi_irq_flag;
uint32_t spi_mst_irq_flag;
uint32_t spi_slv_irq_flag;

void timer0_irq_handle(void)
{
  irq_triggered = 1;                // set timer stopped bool, so that
                                    // system does not wait for another interrupt
  timer_StopTimer(LISOC_TIMER0);    // stop timer
  timer_ClearIRQ(LISOC_TIMER0);     // clear timer 0 IRQ
}

void timer1_irq_handle(void)
{
  irq_triggered = 1;                // set timer stopped bool, so that
                                    // system does not wait for another interrupt
  timer_StopTimer(LISOC_TIMER1);    // stop timer
  timer_ClearIRQ(LISOC_TIMER1);     // clear timer 0 IRQ
}

void timer2_irq_handle(void)
{
  irq_triggered = 1;                // set timer stopped bool, so that
                                    // system does not wait for another interrupt
  timer_StopTimer(LISOC_TIMER2);    // stop timer
  timer_ClearIRQ(LISOC_TIMER2);     // clear timer 0 IRQ
}

void timer_int_test(void)
{
  irq_triggered = 0;
  timer_StopTimer(LISOC_TIMER0);
  timer_Setload(LISOC_TIMER0, LISOC_TIMER_CLK / 1000u * 100);
  NVIC_ClearPendingIRQ(TIMER0_IRQn);
  NVIC_EnableIRQ(TIMER0_IRQn);
  timer_StartTimer(LISOC_TIMER0);
  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while (irq_triggered==0 && IS_TIME_NOT_REACHED(int_tmo)) {
    delay_ms(1); // enter sleep
  }
  if(irq_triggered == 1)
    debug("timer0 interrupt test                      OK.\n");
  else
    debug("timer0 interrupt test                      NG.\n");


  irq_triggered = 0;
  timer_StopTimer(LISOC_TIMER1);
  timer_Setload(LISOC_TIMER1, LISOC_TIMER_CLK / 1000u * 200);
  NVIC_ClearPendingIRQ(TIMER1_IRQn);
  NVIC_EnableIRQ(TIMER1_IRQn);
  timer_StartTimer(LISOC_TIMER1);
  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while (irq_triggered==0 && IS_TIME_NOT_REACHED(int_tmo)) {
    delay_ms(1); // enter sleep
  }
  if(irq_triggered == 1)
    debug("timer1 interrupt test                      OK.\n");
  else
    debug("timer1 interrupt test                      NG.\n");


  irq_triggered = 0;
  timer_StopTimer(LISOC_TIMER2);
  timer_Setload(LISOC_TIMER2, LISOC_TIMER_CLK / 1000u * 300);
  NVIC_ClearPendingIRQ(TIMER2_IRQn);
  NVIC_EnableIRQ(TIMER2_IRQn);
  timer_StartTimer(LISOC_TIMER2);
  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while (irq_triggered==0 && IS_TIME_NOT_REACHED(int_tmo)) {
    delay_ms(1); // enter sleep
  }
  if(irq_triggered == 1)
    debug("timer2 interrupt test                      OK.\n");
  else
    debug("timer2 interrupt test                      NG.\n");

  NVIC_DisableIRQ(TIMER0_IRQn);
  NVIC_DisableIRQ(TIMER1_IRQn);
  NVIC_DisableIRQ(TIMER2_IRQn);
}

void uart1_irq_handle(void)
{
  uint32_t irq_id;
  
  irq_id = UART1_IIR; // clear TX/RX IRQ
  //debug("uart1_irq_handle : %x\n",irq_id);
  if( (irq_id & 0x02u) == 0x02u){
    if (tx_count < uart_str_length) {
      uart1_send(str_tx[tx_count]);
      tx_count++;
    }
  }
  if( (irq_id & 0x04u) == 0x04u){
    str_rx[rx_count] = uart1_recv();  
    rx_count++;
  } 
}

void uart_int_test(void)
{
  uint32_t transmission_complete = 0;

  NVIC_ClearPendingIRQ(UART1_IRQn);   // Ensure Interrupt is not pending
  NVIC_EnableIRQ(UART1_IRQn);         // Enable Interrupts
  uart1_init();
  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while(transmission_complete == 0 && IS_TIME_NOT_REACHED(int_tmo))    // loop until transmission completed
  {
    if ((tx_count==uart_str_length) && (rx_count==uart_str_length)) {
      transmission_complete = 1;
    }
    delay_ms(1);
  }

  if(strcmp(str_tx,str_rx) == 0)
    debug("uart interrupt test                        OK.\n");
  else  
    debug("uart interrupt test                        NG.\n");

  NVIC_DisableIRQ(UART1_IRQn);   //disable both UART1 TX and RX IRQs
}

void wdt_irq_handle(void)
{
  irq_triggered = 1;
  /* Watchdog timer restart command */
  WDT_CRR = 0x76;
}
void rtc_irq_handle(void)
{
  irq_triggered = 1;
  LISOC_RTC->RTC_EOI.rtc_eoi;
}

void wdt_int_test(void)
{
  irq_triggered = 0;

  #if 0
  NVIC_DisableIRQ(WDT_IRQn);  //wdt irq disable  
  //WDT_TORR = 0x06;            //initial counter will be 3fffff
  //WDT_TORR = 0x00;            //initial counter will be ffff
  WDT_CRR = 0x76;             //restart the counter
  NVIC_EnableIRQ(WDT_IRQn);  //wdt irq enable
  #endif
  int_tmo = SysTick1msCount + INT_TIMEOUT*3;
  while (irq_triggered==0 && IS_TIME_NOT_REACHED(int_tmo)) {
    delay_ms(1); // enter sleep
  }
  if(irq_triggered == 1)
    debug("wdt interrupt test                         OK.\n");
  else
    debug("wdt interrupt test                         NG.\n");
}

/* ----------------------------------------- */
/* Individual interrupt handler for GPIOA  */
/*                                           */
void gpioa_irq_handle(void)
{
  uint32_t int_sts;

  int_sts = gpioa_GetIntSts();
  if(int_sts & (1 << PA11))
  {
    gpioa_irq_flag ++;
    gpioa_ClerIntSts(PA11);
  }

  if(int_sts & (1 << PA12))
  {
    gpioa_irq_flag ++;
    gpioa_ClerIntSts(PA12);
  }

  if(int_sts & (1 << PA13))
  {
    gpioa_irq_flag ++;
    gpioa_ClerIntSts(PA13);
  }

  if(int_sts & (1 << PA14))
  {
    gpioa_irq_flag ++;
    gpioa_ClerIntSts(PA14);
  }
}

/* ----------------------------------------- */
/* Individual interrupt handler for GPIOB  */
/*                                           */
void gpiob_irq_handle(void)
{
  uint32_t int_sts;

  int_sts = gpiob_GetIntSts();
  if(int_sts & (1 << PB12))
  {
    gpiob_irq_flag ++;
    gpiob_ClerIntSts(PB12);
  }

  if(int_sts & (1 << PB13))
  {
    gpiob_irq_flag ++;
    gpiob_ClerIntSts(PB13);
  }

  if(int_sts & (1 << PB14))
  {
    gpiob_irq_flag ++;
    gpiob_ClerIntSts(PB14);
  }

  if(int_sts & (1 << PB15))
  {
    gpiob_irq_flag ++;
    gpiob_ClerIntSts(PB15);
  }
}

/*!
    \brief     gpio interrupt test
    \param[in]  none
    \param[out] none
    \retval     none
*/
void gpio_int_test(void)
{
  uint8_t gpio_num = 0;

  NVIC_DisableIRQ(GPIOA_IRQn);  //gpioa irq disable
  NVIC_DisableIRQ(GPIOB_IRQn);  //gpiob irq disable

  for(gpio_num = PA11; gpio_num <= PA14; gpio_num++)
  {
    gpioa_setPinDreict(gpio_num, GPIO_OUT);
  }

  for(gpio_num = PA11; gpio_num <= PA14; gpio_num++)
  {
    gpioa_out(gpio_num, GPIO_LOW);
  }

  for(gpio_num = PB12; gpio_num <= PB15; gpio_num++)
  {
    gpiob_setPinDreict(gpio_num, GPIO_IN);
    gpiob_IntEn(gpio_num);
    gpiob_SetIntType(gpio_num, 1);
    gpiob_SetIntPolarity(gpio_num, 1);
  }

  NVIC_ClearPendingIRQ(GPIOB_IRQn);   // Ensure Interrupt is not pending

  //debug("gpiob rising-edge trigger interrupt test start!\n");
  NVIC_EnableIRQ(GPIOB_IRQn);   //gpiob irq enable

  gpiob_irq_flag = 0;

  // gpioa output the data to Low
  for(gpio_num = PA11; gpio_num <= PA14; gpio_num++)
  {
    gpioa_out(gpio_num, GPIO_HIGH);
  }

  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while (gpiob_irq_flag < 4u && IS_TIME_NOT_REACHED(int_tmo)) {
    __WFE(); // enter sleep
  }

  if(gpiob_irq_flag == 4u)
    debug("gpiob rising-edge trigger interrupt test   OK.\n");
  else
    debug("gpiob rising-edge trigger interrupt test   NG.\n");

  //debug("gpiob falling-edge trigger interrupt test start!\n");

  for(gpio_num = PB12; gpio_num <= PB15; gpio_num++)
  {
    gpiob_SetIntType(gpio_num, 1);
    gpiob_SetIntPolarity(gpio_num, 0);
  }

  gpiob_irq_flag = 0;
  // gpioa output the data to Low
  for(gpio_num = PA11; gpio_num <= PA14; gpio_num++)
  {
    gpioa_out(gpio_num, GPIO_LOW);
  }

  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while (gpiob_irq_flag < 4u && IS_TIME_NOT_REACHED(int_tmo)) {
    __WFE(); // enter sleep
  }

  if(gpiob_irq_flag == 4u)
    debug("gpiob falling-edge trigger interrupt test  OK.\n");
  else
    debug("gpiob falling-edge trigger interrupt test  NG.\n");

/***************gpioa interrupt test********************************/
  NVIC_DisableIRQ(GPIOB_IRQn);  //gpiob irq disable

  for(gpio_num = PB12; gpio_num <= PB15; gpio_num++)
  {
    gpiob_setPinDreict(gpio_num, GPIO_OUT);
  }

  for(gpio_num = PB12; gpio_num <= PB15; gpio_num++)
  {
    gpiob_out(gpio_num, GPIO_LOW);
  }

  for(gpio_num = PA11; gpio_num <= PA14; gpio_num++)
  {
    gpioa_setPinDreict(gpio_num, GPIO_IN);
    gpioa_IntEn(gpio_num);
    gpioa_SetIntType(gpio_num, 1);
    gpioa_SetIntPolarity(gpio_num, 1);
  }

  NVIC_ClearPendingIRQ(GPIOA_IRQn);   // Ensure Interrupt is not pending

  //debug("gpioa rising-edge trigger interrupt test start!\n");
  NVIC_EnableIRQ(GPIOA_IRQn);   //gpioa irq enable

  gpioa_irq_flag = 0u;

  for(gpio_num = PB12; gpio_num <= PB15; gpio_num++)
  {
    gpiob_out(gpio_num, GPIO_HIGH);
  }

  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while (gpioa_irq_flag < 4u && IS_TIME_NOT_REACHED(int_tmo)) {
    __WFE(); // enter sleep
  }

  if(gpioa_irq_flag == 4u)
    debug("gpioa rising-edge trigger interrupt test   OK.\n");
  else
    debug("gpioa rising-edge trigger interrupt test   NG.\n");

  //debug("gpioa falling-edge trigger interrupt test start.\n");

  for(gpio_num = PA11; gpio_num <= PA14; gpio_num++)
  {
    gpioa_SetIntType(gpio_num, 1);
    gpioa_SetIntPolarity(gpio_num, 0);
  }

  gpioa_irq_flag = 0u;

  for(gpio_num = PB12; gpio_num <= PB15; gpio_num++)
  {
    gpiob_out(gpio_num, GPIO_LOW);
  }

  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while (gpioa_irq_flag < 4u && IS_TIME_NOT_REACHED(int_tmo)) {
    __WFE(); // enter sleep
  }

  if(gpioa_irq_flag == 4u)
    debug("gpioa falling-edge trigger interrupt test  OK.\n");
  else
    debug("gpioa falling-edge trigger interrupt test  NG.\n");

  NVIC_DisableIRQ(GPIOA_IRQn);  //gpioa irq disable
  NVIC_DisableIRQ(GPIOB_IRQn);  //gpiob irq disable
}

/*!
    \brief      qspi interrupt handle function
    \param[in]  none
    \param[out] none
    \retval     none
*/
void qspi_irq_handle(void)
{
    //uint32_t irq_sts;

    qspi_irq_flag = 1;
    //irq_sts = SPIM_GetIntSts();
    //debug("qspi irq sts:%x!\n",irq_sts);

    SPIM_ClerIntSts();
    SPIM_MaskInt(SPI_INT_DISABLE);
}

/*!
    \brief    qspi  interrupt test
    \param[in]  none
    \param[out] none
    \retval     none
*/
void qspi_int_test(void)
{
  uint8_t flash_buff[64*4];


  NVIC_DisableIRQ(QSPI_IRQn);

  SPIF_init();
  SPIM_MaskInt(0x3F);

  SSI0_TXFTLR = 8;
  SSI0_RXFTLR = 8;

  NVIC_ClearPendingIRQ(QSPI_IRQn);   // Ensure Interrupt is not pending

  //debug("qspi interrupt test start\n");
  qspi_irq_flag = 0;

  NVIC_EnableIRQ(QSPI_IRQn);

  /* erase sector #0 (sector size = 4KB) */
  //SPIF_BlockErase64K(0u);

  /* program page #0 (page size = 256B) */
  //memcpy((void *)_aclisoc_buf32, (void *)_aclisoc_flash, sizeof(_aclisoc_flash));
  //SPIF_Program(0u, (uint8_t *)_aclisoc_buf32, sizeof(_aclisoc_flash));
  //SPIM_TxRx(0X02,0u, (uint8_t *)_aclisoc_flash, sizeof(_aclisoc_flash),0);

  SPIF_ReadData(0, flash_buff, 36);

  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while (qspi_irq_flag == 0u && IS_TIME_NOT_REACHED(int_tmo)) {
    __WFE(); // enter sleep
  }

  if(qspi_irq_flag == 1u)
    debug("qspi interrupt test                        OK.\n");
  else
    debug("qspi interrupt test                        NG.\n");

  NVIC_DisableIRQ(QSPI_IRQn);
}

/*!
    \brief      spi master interrupt handle function
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_mst_irq_handle(void)
{
    uint8_t tmp[8];
    uint32_t irq_sts;

    spi_mst_irq_flag = 1;
    irq_sts = spi_master_GetIntSts();
    //debug("spi master irq:%x!\n",irq_sts);
    if((irq_sts & SSI0_ISR_RXFIS) >> SSI0_ISR_RXFIS_BITOFS)
    {
      //debug("recv fifo full!\n");
      spi_master_int_recv(tmp, 8);
    }

    spi_master_ClrIntSts();

}

/*!
    \brief      spi slave interrupt handle function
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_slv_irq_handle(void)
{
    uint8_t tmp[8];
    uint32_t irq_sts;

    spi_slv_irq_flag = 1;
    irq_sts = spi_slave_GetIntSts();
    //debug("spi slave irq:%x!\n",irq_sts);
    if((irq_sts & SSI0_ISR_RXFIS) >> SSI0_ISR_RXFIS_BITOFS)
    {
      //debug("recv fifo full!\n");
      spi_slave_recv(tmp, 8);
    }
    spi_slave_ClrIntSts();
    spi_slave_SetIntMask(0);
}

void spi_int_test(void)
{
  uint8_t txbuff[9] = {0x11, 0x22, 0x33, 0x44, 0x55,0x66,0x77,0x88,0x99};

  NVIC_DisableIRQ(SPIM_IRQn);
  NVIC_DisableIRQ(SPIS_IRQn);

  spi_master_init();
  spi_slave_init();

  //debug("spi interrupt test start.\n");

  spi_mst_irq_flag = 0;
  spi_slv_irq_flag = 0;

  NVIC_ClearPendingIRQ(SPIM_IRQn);
  NVIC_ClearPendingIRQ(SPIS_IRQn);

  NVIC_EnableIRQ(SPIM_IRQn);
  NVIC_EnableIRQ(SPIS_IRQn);

  spi_master_send((uint8_t*)txbuff, 9);

  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while (spi_mst_irq_flag == 0u && IS_TIME_NOT_REACHED(int_tmo)) {
   __WFE(); // enter sleep
  }

  if(spi_mst_irq_flag == 1u)
    debug("spi master interrupt test                  OK.\n");
  else
    debug("spi master interrupt test                  NG.\n");

   int_tmo = SysTick1msCount + INT_TIMEOUT;
   while (spi_slv_irq_flag == 0u && IS_TIME_NOT_REACHED(int_tmo)) {
     __WFE(); // enter sleep
   }

  if(spi_slv_irq_flag == 1u)
    debug("spi slave interrupt test                   OK.\n");
  else
    debug("spi slave interrupt test                   NG.\n");

  NVIC_DisableIRQ(SPIM_IRQn);
  NVIC_DisableIRQ(SPIS_IRQn);
}

void i2c0_irq_handle(void)
{
  irq_triggered = 1;
  I2C0_ENABLE = 0;
}

void i2c1_irq_handle(void)
{
  irq_triggered = 1;
  I2C1_ENABLE = 0;
}

void i2c2_irq_handle(void)
{
  irq_triggered = 1;
  //I2C2_ENABLE = 0;
}

void i2c_int_test(void)
{
  irq_triggered = 0;
  I2C0_ENABLE = 1;
  //I2C0_INTR_MASK = 0;
  NVIC_ClearPendingIRQ(I2C0_IRQn);
  NVIC_EnableIRQ(I2C0_IRQn); 
  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while (irq_triggered==0 && IS_TIME_NOT_REACHED(int_tmo)) {
    delay_ms(1); // enter sleep
  }
  if(irq_triggered == 1)
    debug("i2c0 interrupt test                        OK.\n");
  else
    debug("i2c0 interrupt test                        NG.\n");

  NVIC_DisableIRQ(I2C0_IRQn);

  irq_triggered = 0;
  I2C1_ENABLE = 1;
  NVIC_ClearPendingIRQ(I2C1_IRQn);
  NVIC_EnableIRQ(I2C1_IRQn); 
  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while (irq_triggered==0 && IS_TIME_NOT_REACHED(int_tmo)) {
    delay_ms(1); // enter sleep
  }
  if(irq_triggered == 1)
    debug("i2c1 interrupt test                        OK.\n");
  else
    debug("i2c1 interrupt test                        NG.\n");

  NVIC_DisableIRQ(I2C1_IRQn);

  #if 0
  irq_triggered = 0;
  I2C2_ENABLE = 1;
  NVIC_ClearPendingIRQ(I2C2_IRQn);
  NVIC_EnableIRQ(I2C2_IRQn); 
  int_tmo = SysTick1msCount + INT_TIMEOUT;
  while (irq_triggered==0 && IS_TIME_NOT_REACHED(int_tmo)) {
    delay_ms(1); // enter sleep
  }
  if(irq_triggered == 1)
    debug("i2c2 interrupt test\tOK.\n");
  else
    debug("i2c2 interrupt test\tNG.\n");

  NVIC_DisableIRQ(I2C2_IRQn);
  #endif
}

void rtc_int_test(void)
{
  irq_triggered = 0;

  LISOC_RTC->RTC_CLR_W = 0x0;
  LISOC_RTC->RTC_CMR_W = 0x1;
  LISOC_RTC->RTC_CPSR_W = 32768; //1s
  LISOC_RTC->RTC_CCR_W |= 0x15;

  NVIC_EnableIRQ(RTC_IRQn);

  int_tmo = SysTick1msCount + INT_TIMEOUT*3;
  while (irq_triggered==0 && IS_TIME_NOT_REACHED(int_tmo)) {
    delay_ms(1); // enter sleep
  }
  if(irq_triggered == 1)
    debug("rtc interrupt test                         OK.\n");
  else
    debug("rtc interrupt test                         NG.\n");

  NVIC_DisableIRQ(RTC_IRQn);
}

/*!
    \brief      interrupt test
    \param[in]  none
    \param[out] none
    \retval     none
*/
void interrupt_test(void)
{
  rtc_int_test();
  //uart_int_test();
  timer_int_test();
  gpio_int_test();
  qspi_int_test();
  spi_int_test();
  i2c_int_test();
  wdt_int_test();
}

