/*************************************************************************
 * DISCLAIMER                                                            *
 * Services performed by FREESCALE in this matter are performed          *
 * AS IS and without any warranty. CUSTOMER retains the final decision   *
 * relative to the total design and functionality of the end product.    *
 * FREESCALE neither guarantees nor will be held liable by CUSTOMER      *
 * for the success of this project. FREESCALE disclaims all warranties,  *
 * express, implied or statutory including, but not limited to,          *
 * implied warranty of merchantability or fitness for a particular       *
 * purpose on any hardware, software ore advise supplied to the project  *
 * by FREESCALE, and or any product resulting from FREESCALE services.   *
 * In no event shall FREESCALE be liable for incidental or consequential *
 * damages arising out of this agreement. CUSTOMER agrees to hold        *
 * FREESCALE harmless against any and all claims demands or actions      *
 * by anyone on account of any damage, or injury, whether commercial,    *
 * contractual, or tortuous, rising directly or indirectly as a result   *
 * of the advise or assistance supplied CUSTOMER in connection with      *
 * product, services or goods supplied under this Agreement.             *
 *************************************************************************/
/*******************************************************************
  Copyright (c) 2011 Freescale Semiconductor
  \file     	Main.c
  \brief    	Smart Card Reader for MC9S08JM60
  \author   	Freescale Semiconductor
  \version    0.1
  \date     	15/Aug/2011
*********************************************************************/
#include <hidef.h>          /* for EnableInterrupts macro */

#include "SmartCard.h"
#include "SCI.h"
#include "CLK.h"
#include "USB_User_API.h"   /* USB API for USB Module */

#pragma MESSAGE DISABLE C1420 // Result of function call is ignored
//#pragma MESSAGE DISABLE C4000 // Condition always true
//#pragma MESSAGE DISABLE C5702 // Local variable not referenced

#define ATR_Buffer_Max   33
#define SC_WaitingTime   6000

byte sc_cmd_status;
byte sc_cmd_buffer[64];
byte sc_resp_buffer[64];

byte SC_Active = 0;
byte ATR_Buffer[ATR_Buffer_Max];
byte ATR_TA, ATR_TB, ATR_TC, ATR_TD;
byte ATR_Historical[10];
byte sc_inserted;
byte sc_inserted_old;

/******************************************************************************
 * Function:        void Delay(word time)
 * Input:           time 
 * Output:          None
 * Overview:        Whe Bus frequency = 24MHz. Clock to Smart Card f = 1.5MHz.
 *                  It will delay time cycles of 1/f
 *****************************************************************************/
void Delay(word time)
{ 
  time = time / 3;
  while(time --) // each cycle will consume 48 Bus cycles 
  { 
    __asm PSHA;  // 2 cycle
    __asm PULA;  // 3 cycle
    __asm PSHA;  // 2 cycle
    __asm PULA;  // 3 cycle
    __asm PSHA;  // 2 cycle
    __asm PULA;  // 3 cycle
    __asm PSHA;  // 2 cycle
    __asm PULA;  // 3 cycle

  }
}


void SC_Init(void)
{
  SC_POWER_DD = 1;     // Output
  SC_RESET_DD = 1;     // Output
  SC_PRESENCE_DD = 0;  // Input

  SC_POWER  = SC_POWER_OFF;
  SC_RESET  = SC_RESET_LOW;
  sc_inserted = SC_PRESENCE;
  sc_inserted_old = SC_NO_CARD;
}

void SC_PowerOff(void)
{
  SC_RESET  = SC_RESET_LOW;
  Delay(60000);
  CLK_Disable();
  Delay(60000);
  SC_POWER  = SC_POWER_OFF;
  Delay(60000);
}


void SC_ColdReset(void)
{ unsigned char i,temp;

  Delay(60000);
  SC_POWER  = SC_POWER_ON;
  Delay(60000);
  CLK_Enable();
  Delay(400);
  for(i = 0;i < ATR_Buffer_Max;i ++)
  {
    ATR_Buffer[i] = 0;
  }
  SC_RESET  = SC_RESET_HIGH;
  Delay(100);
  (void)(SCI1S1);
  (void)(SCI1D); // clear false data  
  Delay(600);
  for(i = 0;i < 13;i ++)
  {
    if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
    {
      ATR_Buffer[i] = temp;
    }
    else
    {
      ATR_Buffer[i] = 0xff;
    }
  }
}


void SC_ATR_Decode(void)
{ unsigned char i,j;

  ATR_TA = 0;
  ATR_TB = 0;
  ATR_TC = 0;
  ATR_TD = 0;
  for(i = 0;i < 10;i ++)
  {
    ATR_Historical[i] = 0;
  }
  if(ATR_Buffer[0] == 0x3B && ATR_Buffer[1] == 0x69)  // TB1 TC1, 9 historical chars
  {
    i = 2;
    ATR_TB = ATR_Buffer[i++];
    ATR_TC = ATR_Buffer[i++];
    for(j = 0;j < 9;j ++)
    {
      ATR_Historical[j] = ATR_Buffer[i++];;
    }

    SC_Active = 1;
  }
}


void SC_Start(void)
{
  SC_ColdReset();
  SC_ATR_Decode();
  sc_cmd_status = SC_CMD_IDLE;
   
}

// sc_resp_buffer[0] is the length of response including data and SW1 SW2
byte SC_Send_Response(void)
{ unsigned char i;

  for(i = 0;i <= sc_resp_buffer[0];i ++)
  {
    EP4_Buffer[i] = sc_resp_buffer[i];
  }
  EndPoint_IN(EP4,sc_resp_buffer[0] + 1);
  
  return 0;
}

byte SC_Send_Response_Int(byte inserted)
{ 
  EP2_Buffer[1] = inserted;
 
  EndPoint_IN(EP2,8);
  
  return 0;
}



/******************************************************************************
 * Function:        SC_servo(void)
 * Overview:        Process the command in command buffer and store the response
 *                  in response buffer. 
 *                  Case 1 No command data field   No response data field
 *                  Case 2 No command data field   Response data field
 *                  Case 3 Command data field      No response data field
 *                  Case 4 Command data field      Response data field
 *****************************************************************************/
byte SC_servo(void)
{ unsigned char i = 0,temp = 0;
  
  sc_inserted = SC_PRESENCE;

  if(sc_inserted != sc_inserted_old)
  {
    sc_inserted_old = sc_inserted;
    SC_Send_Response_Int(sc_inserted + 1);
    
    if(sc_inserted == SC_CARD_INSERTED) 
      {
         SC_Start( );
      }
    else
      {
        SC_Active = 0;
        SC_PowerOff( ); 
      }
  }
  
  if(sc_inserted == SC_CARD_INSERTED && SC_Active == 0)
  {
    SC_PowerOff( );
    SC_Start( );
  }

  if(sc_cmd_status == SC_CMD_RECEIVED)
  { 
    if(sc_cmd_buffer[0] <= 0x03 || SC_Active != 1 || sc_inserted == SC_NO_CARD)
    {
      sc_resp_buffer[0] = 0x01;
      sc_resp_buffer[1] = sc_inserted + 1;
      sc_cmd_status = SC_CMD_IDLE;
      SC_Send_Response( );
      //EnableInterrupts;
      return 0;
    }
       
    SCI1_SendChar(sc_cmd_buffer[1]);  // CLA
    SCI1_SendChar(sc_cmd_buffer[2]);  // INS
    SCI1_SendChar(sc_cmd_buffer[3]);  // P1
    SCI1_SendChar(sc_cmd_buffer[4]);  // P2
  
    if(sc_cmd_buffer[0] == 0x04)                       //case 1
      {
        SCI1_SendChar(0x00);               // P3 = 0;
        if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
        {
          while(temp == 0x60)
          {
            if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS);
            asm nop;
          };
          
          if(((temp & 0xF0) == 0x60) || ((temp & 0xF0) == 0x90))
          {
            asm nop;
            sc_resp_buffer[1] = temp;      // SW1
            if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
            {
              sc_resp_buffer[2] = temp;    // SW2
              sc_resp_buffer[0] = 2;       // response lenth
              
              SC_Send_Response( );
            }
          }
        }
      }
    else if(sc_cmd_buffer[0] == 0x05)                  //case 2
      {
        SCI1_SendChar(sc_cmd_buffer[5]);   // P3 = Le;
        if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
        {
          while(temp == 0x60)
          {
            if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS);
            asm nop;
          };
          
          if(((temp & 0xF0) == 0x60) || ((temp & 0xF0) == 0x90))
          {
            asm nop;
            sc_resp_buffer[1] = temp;      // SW1
            if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
            {
              sc_resp_buffer[2] = temp;    // SW2
              sc_resp_buffer[0] = 2;       // response lenth
              
              SC_Send_Response( );
            }
          }
          else if(temp == sc_cmd_buffer[2])      // INS
          {
            for(i = 1;i <= sc_cmd_buffer[5];i ++)
            {
              SCI1_RecvChar(&temp, SC_WaitingTime);
              sc_resp_buffer[i] = temp;
            }
            if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
            {
              sc_resp_buffer[i] = temp;          // SW1
              if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
              {
                sc_resp_buffer[++i] = temp;      // SW2
                sc_resp_buffer[0] = i;
                
                SC_Send_Response( );
              }
            }
          }
        }
      }
    else if(sc_cmd_buffer[0] == sc_cmd_buffer[5] + 0x05)   //case 3
      {
        SCI1_SendChar(sc_cmd_buffer[5]);   // P3 = Lc;
        if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
        {
          while(temp == 0x60)
          {
            if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS);
          };
          
          if(((temp & 0xF0) == 0x60) || ((temp & 0xF0) == 0x90))
          {
            sc_resp_buffer[1] = temp;      // SW1
            if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
            {
              sc_resp_buffer[2] = temp;    // SW2
              sc_resp_buffer[0] = 2;       // response lenth
              
              SC_Send_Response( );
            }
          }
          else if(temp == sc_cmd_buffer[2])      // INS
          {
            for(i = 1;i <= sc_cmd_buffer[5];i ++)
            {
              SCI1_SendChar(sc_cmd_buffer[5+i]);
            }
            if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
            {
              sc_resp_buffer[1] = temp;          // SW1
              if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
              {
                sc_resp_buffer[2] = temp;        // SW2
                sc_resp_buffer[0] = 2;
                
                SC_Send_Response( );
              }
            }
          }
        }
      }
    else if(sc_cmd_buffer[0] == sc_cmd_buffer[5] + 0x06)   //case 4
      {
        SCI1_SendChar(sc_cmd_buffer[5]);   // P3 = Lc;
        if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
        {
          while(temp == 0x60)
          {
            if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS);
          };
          
          if(((temp & 0xF0) == 0x60) || ((temp & 0xF0) == 0x90))
          {
            sc_resp_buffer[1] = temp;      // SW1
            if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
            {
              sc_resp_buffer[2] = temp;    // SW2
              sc_resp_buffer[0] = 2;       // response lenth
              
              SC_Send_Response( );
            }
          }
          else if(temp == sc_cmd_buffer[2])      // INS
          {
            for(i = 1;i <= sc_cmd_buffer[5];i ++)
            {
              SCI1_SendChar(sc_cmd_buffer[5+i]);
            }
            if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
            {
              sc_resp_buffer[1] = temp;          // SW1
              if(SCI1_RecvChar(&temp, SC_WaitingTime) == SUCCESS)
              {
                sc_resp_buffer[2] = temp;        // SW2
                sc_resp_buffer[0] = 2;
                if(sc_resp_buffer[1] == 0x90 && sc_resp_buffer[2] == 0x00)
                {                                // Get response
                  sc_cmd_buffer[0] = 0x05;
                  sc_cmd_buffer[1] = 0x00;       // CLA
                  sc_cmd_buffer[2] = 0xC0;       // INS
                  sc_cmd_buffer[3] = 0x00;
                  sc_cmd_buffer[4] = 0x00;
                  sc_cmd_buffer[5] = sc_cmd_buffer[5+i];
                  return 0;
                }
                
                SC_Send_Response( );
              }
            }
          }
        }
      }
    
    sc_cmd_status = SC_CMD_IDLE;
  }
  
  return 0;

}

