#include "iolpc2368.h"
#include "ucos_ii.h"
#include "cpu.h"
#include "app_serv.h"
#include "coin.h"
#include "data.h"
#include "datadesc.h"
#include "modem.h"
#include <stdlib.h>


OS_STK  CoinTaskStk[COIN_TASK_STK_SIZE];

void  InitImpInput(void);

CPU_INT32U  CoinImpCounter;
CPU_INT08U  coin_enabled;
static CPU_INT32U coin_pulse = 5000;
static CPU_INT32U coin_pause = 20;
static CPU_INT32U coin_span = 1000;
static char pend_coin_counter = 0;
static CPU_INT32U pend_coin_timestamp;


void UpdateImpParams(void)
{
    CPU_INT32U len, delta, pause;
    GetData(&CoinPulseLenDesc, &len, 0, DATA_FLAG_SYSTEM_INDEX);
    GetData(&CoinPauseLenDesc, &pause, 0, DATA_FLAG_SYSTEM_INDEX);
    GetData(&CoinPulseDeltaDesc, &delta, 0, DATA_FLAG_SYSTEM_INDEX);

    #if OS_CRITICAL_METHOD == 3
    OS_CPU_SR  cpu_sr = 0;
    #endif
    OS_ENTER_CRITICAL();

    coin_pulse = len * 100;
    coin_span =  delta * 100;
    coin_pause = pause;
    
    OS_EXIT_CRITICAL();
}
        
        
void CoinTask(void *p_arg)
{
    CPU_INT32U enable_coin;
    CPU_INT32U last_coin_count = GetCoinCount();
    CPU_INT32U last_coin_time = OSTimeGet();
    CPU_INT32U last_settings_time = OSTimeGet();

    UpdateImpParams();
    
    while(1)
    {
        if (OSTimeGet() - last_settings_time > 1000)
        {
            last_settings_time = OSTimeGet();
            GetData(&EnableCoinDesc, &enable_coin, 0, DATA_FLAG_SYSTEM_INDEX);  
            UpdateImpParams();
        }

        OSTimeDly(1);
        
        if (enable_coin && coin_enabled)
        {
            FIO0CLR_bit.P0_24  = 1;
            
            #if OS_CRITICAL_METHOD == 3
            OS_CPU_SR  cpu_sr = 0;
            #endif
            OS_ENTER_CRITICAL();
            if (pend_coin_counter)
            {
                if (OSTimeGet() - pend_coin_timestamp > coin_pause)
                {
                    pend_coin_counter = 0;
                    CoinImpCounter++;
                }
            }
            OS_EXIT_CRITICAL();
            
            CPU_INT32U curr_coin_count = GetCoinCount();
            if (curr_coin_count)
            {
                if (last_coin_count == curr_coin_count)
                {
                    if (OSTimeGet() - last_coin_time > 500)
                    {
                        PostUserEvent(EVENT_COIN_INSERTED);
                    }
                }
                else
                {
                    last_coin_count = curr_coin_count;
                    last_coin_time = OSTimeGet();
                }
            }
            else
            {
                last_coin_time = OSTimeGet();
            }
        }
        else
        {
            FIO0SET_bit.P0_24  = 1;
            if (enable_coin && GetCoinCount())
            {
                PostUserEvent(EVENT_COIN_INSERTED);
            }
            else
            {
                GetResetCoinCount();
            }
            OSTimeDly(500);
        }
    }
}

void CoinDisable(void)
{
    coin_enabled = 0;
}

void CoinEnable(void)
{
    coin_enabled = 1;
}

// получить число монет
CPU_INT32U GetCoinCount(void)
{
  #if OS_CRITICAL_METHOD == 3
  OS_CPU_SR  cpu_sr = 0;
  #endif
  OS_ENTER_CRITICAL();
  CPU_INT32U ctr = CoinImpCounter;
  OS_EXIT_CRITICAL();
  return ctr;
}

// получить число монет и сбросить счетчик
CPU_INT32U GetResetCoinCount(void)
{
  #if OS_CRITICAL_METHOD == 3
  OS_CPU_SR  cpu_sr = 0;
  #endif
  OS_ENTER_CRITICAL();
  CPU_INT32U ctr = CoinImpCounter;
  CoinImpCounter = 0;
  OS_EXIT_CRITICAL();
  return ctr;
}

// инициализация монетоприемника
void InitCoin(void)
{
  CoinImpCounter = 0;
  coin_enabled = 0;
  InitImpInput();
  
  OSTaskCreate(CoinTask, (void *)0, (OS_STK *)&CoinTaskStk[COIN_TASK_STK_SIZE-1], COIN_TASK_PRIO);
}


void InputCapture_ISR(void)
{
  CPU_INT08U ir = T3IR;
  static CPU_INT32U period = 0;
  T3IR = 0xFF;

  if (ir & 0x10)
    {// CR0 interrupt
  
      if (FIO0PIN_bit.P0_23)
        {// пришел задний фронт
          CPU_INT32U cr=T3CR0;
          cr -= period;
          if ((cr > (coin_pulse - coin_span))
               &&  (cr < (coin_pulse + coin_span)))
          {
              pend_coin_counter = 1;
              pend_coin_timestamp = OSTimeGet();
          }
        }
      else
        {// пришел передний фронт
          period = T3CR0;
          pend_coin_counter = 0;
        }
    }
}


extern CPU_INT32U  BSP_CPU_PclkFreq (CPU_INT08U  pclk);

/*
P0.23	MK_P9	IMPULSE OUTPUT (импульсный выход монетоприемника)
P0.24	MK_P8	INHIBIT (блокировка)
*/
// инициализация импульсного входа
// используется CAP3.0
void  InitImpInput (void)
{
    #define INPUT_CAPTURE_FREQ  100000  // частота тактирования частотных входов
  
    CPU_INT32U  pclk_freq;
    CPU_INT32U  rld_cnts;

    #if OS_CRITICAL_METHOD == 3
    OS_CPU_SR  cpu_sr = 0;
    #endif

    OS_ENTER_CRITICAL();

    PCONP_bit.PCTIM3 = 1;
    PCLKSEL1_bit.PCLK_TIMER3 = 2;
      
    PINSEL1_bit.P0_23 = 0x3;
    PINMODE1_bit.P0_23 = 0;
    FIO0DIR_bit.P0_23  = 0;
    FIO0MASK_bit.P0_23 = 0;

    // inhibit
    PINSEL1_bit.P0_24 = 0x0;
    PINMODE1_bit.P0_24 = 0;
    FIO0DIR_bit.P0_24  = 1;
    FIO0MASK_bit.P0_24 = 0;
    FIO0SET_bit.P0_24  = 1;
        
    pclk_freq         =   BSP_CPU_PclkFreq(23);
    rld_cnts          =   pclk_freq / INPUT_CAPTURE_FREQ;

    T3CTCR_bit.CTM    =   0;
    T3CTCR_bit.CIS    =   0;          // select CAP3.0 input
    T3PR              =   rld_cnts-1;
    T3MCR             =   0;
    T3CCR             =   0x07;
    T3EMR             =   0;
    T3TCR             =   0x03;
    T3TCR             =   0x01;
    
    VICINTSELECT     &= ~(1 << VIC_TIMER3);
    VICVECTADDR27     =  (CPU_INT32U)InputCapture_ISR;
    VICVECTPRIORITY27 =  10;                       
    VICINTENABLE      =  (1 << VIC_TIMER3);       

    T3IR = 0xFF;
    
    OS_EXIT_CRITICAL();
}

