/******************************************************************************
*                                                                             *
*              Copyright (C),  Philips Semiconductors SLH                     *                                                                             *
*                                                                             *
*  All rights are reserved. Reproduction in whole or in part is prohibited    *
*           without the written consent of the copyright owner.               *
*                                                                             *
*  Philips reserves the right to make changes without notice at any time.     *
* Philips makes no warranty, expressed, implied or statutory, including but   *
* not limited to any implied warranty of merchantibility or fitness for any   *
*   particular purpose, or that the use will not infringe any third party     *
* patent, copyright or trademark. Philips must not be liable for any loss or  *
*                      damage arising from its use.                           *
*                                                                             *
*******************************************************************************
*                                                                             *
*       Project: 336355/105 - Control SW Library for HTRC110/HTRC120/HITAG2   *
*                                                                             *
*       File: HT2_C.C                                                         *
*       Author:  St. de Zeeuw                                                 *
*                                                                             *
*******************************************************************************
*      DATE      *          CHANGES DONE                        *     BY      *
*******************************************************************************
*                *                                              *             *
*  Dec 04,1997   * Start implementation                         *  de Zeeuw   *
*  Dec 10,1997   * Version 1.0, tested Version                  *  de Zeeuw   *
*  Apr 27,1998   * Version 2.0                                  *  de Zeeuw   *
*                *                                              *             *
*******************************************************************************/

#include "portab.h"
#include "reg51.h"
#include "hitag2.h"

#ifdef HTRC110
#include "htrc110.h"
#endif

#include "HTRC120.H"


#pragma regparms



/******************************************************************************
*                                                                             *
* Export declarations                                                         *
*                                                                             *
******************************************************************************/

UBYTE idata * Byte_Addr;        /* Pointer for actual stored byte            */
BOOL          Cypher;           /* Indicates authentication modus            */
UBYTE         HT_Command;       /* Protocol modus variable                   */
UBYTE         NBit;             /* Number of bits requested to read/write    */
UBYTE         Protocol_State;   /* Protocol state: see #define P_....        */

void (code *Protocol_Callback)(void) = 0;

extern UBYTE code MSB_TABLE[8];



void Set_Memory_Address (UBYTE idata * mem_addr)
/******************************************************************************
*                                                                             *
* Description:                                                                *
* Sets the memory start address to which the command and data are written     *
* and read. Should be re-defined after reading/writing to optimize memory     *
* usage. Must be called before protocol start to first initialize the start   *
* address.                                                                    *
*                                                                             *
* Parameters:                                                                 *
*   mem_addr: Pointer to idata memory; the protocol always uses sucessive     *
*             memory addresses.                                               *
*                                                                             *                               
* Return: none                                                                *
******************************************************************************/
{
  Byte_Addr = mem_addr;
}



BOOL Protocol_Active (void)
/******************************************************************************
*                                                                             *
* Description:                                                                *
* Routine to proof whether the protocol is active or not.                     *
* a decoder error has occured or not.                                         *
*                                                                             *
* Parameters:none                                                             *
*                                                                             *                               
* Return: TRUE, if active, FALSE if finished                                  *
*                                                                             *                  
******************************************************************************/
{
  return Protocol_State != P_STOP;
}



UBYTE Decoder_Error (void)
/******************************************************************************
*                                                                             *
* Description:                                                                *
* At the end of the protocol this routine can be used to examine whether      *
* a decoder error has occured or not.                                         *
*                                                                             *
* Parameters: none                                                            *
*                                                                             *                               
* Return: D_DELTA_ERROR or D_TIMEOUT, in case an decoder error has occured,   *
*         C_TIMEOUT, in case a HTRC120 error has occured,                     *  
*         else FALSE                                                          *
*                                                                             *                  
******************************************************************************/
{
  if(Decoder_State==D_TIMEOUT || Decoder_State==D_DELTA_ERROR || 
     Decoder_State == C_TIMEOUT)
    return Decoder_State;

  return FALSE;
}


void Generate_Command (UBYTE command, UBYTE Page_Adr, UBYTE Cmd_Repeat)
/******************************************************************************
*                                                                             *
* Description:                                                                *
* This routine builds the proper command sequence of the HITAG2 and           *
* stores the bit string in the memory starting at Byte_Addr.                  * 
* The start address should be defined with Set_Memory_Address.                *
*                                                                             *
* Parameters:                                                                 *
*   command:    wanted HITAG2 command, seedefinitions in hitag2.h             *
*   Page_Adr:   address of page to be written to (1..7), without meaning for   *
*               HALT/START_AUTHENT                                            *
*   Cmd_Repeat: Number of command repitions, Cmd_Repeat >=2 ,meaningless for  *
*               START_AUTHENT                                                 *
*                                                                             *                               
* Return: none                                                                *
*                                                                             *                  
******************************************************************************/
{
   UBYTE temp, counter;

   NBit = 5 * Cmd_Repeat;
 
   switch (command)     /* the definitions of the HITAG2 command, see spec*/
   {
   	case HALT:  
         temp       = 0x01;
         HT_Command = HT_HALT;
         break;	
      
      case READ_PAGE_INVERTED:   
         temp       = 0x08 | Page_Adr;
         HT_Command = HT_READ;
         break;

      case READ_PAGE:   
         temp       = 0x18 | Page_Adr;
         HT_Command = HT_READ;
         break;

   	case WRITE_PAGE:   
         temp       = 0x10 | Page_Adr;
         HT_Command = HT_WRITE;
         break;
      
   	case START_AUTHENT:   
         temp       = 0x18;
         HT_Command = HT_AUTHENT;
         NBit       = 5;             /* Override repeat count */
         break;
      
      default:             /*  nothing usefuls happens now*/
      return;
   }

   temp = temp << 3;

   Byte_Addr--;
   temp=~temp;
   counter=0;
   do                    /*  and now the complete command stream is build*/
   {
      if (counter % 8 == 0)
      {
         Byte_Addr++;     /* next byte */  
         *Byte_Addr = 0;   /* initialize... */
      }

      if (counter % 5 == 0) temp =~temp; /* take inverted command*/
 
      if(temp & MSB_TABLE[counter%5])   /* save this bit */
         *Byte_Addr|=MSB_TABLE[counter%8];

      counter ++; 
   }      
   while (counter != NBit);	     

   Byte_Addr -= ((NBit-1)/8);   /* reset Byte_Addr to initial value */

}


void Execute_Command (void)
/******************************************************************************
*                                                                             *
* Description:                                                                *
* This routine initializes and starts the protocol state machine for all      *
* HITAG2 commands with the exception of START_AUTHENT.                        *
*                                                                             *
* Parameters:none                                                             *
* Return:    none                                                             *
*                                                                             *                  
******************************************************************************/
{
   Protocol_State   = P_START;
   next_HT_state();	
}



void Set_Communication_Mode (BOOL Cypher_Flag)
/******************************************************************************
*                                                                             *
* Description:                                                                *
* Defines whether authentication takes place in plain or encrypted.           *
*                                                                             *
* Parameters:                                                                 *
* Cypher_Flag: PASSWORD: password mode; CRYPTO: crypto mode                   *
*                                                                             *                               
* Return: none                                                                *
*                                                                             *                               
******************************************************************************/
{
   Cypher           = Cypher_Flag;
}




/******************************************************************************
*******************************************************************************
*                                                                             *
*   and now the subroutines.....                                              *
*                                                                             *
*******************************************************************************
******************************************************************************/


void Protocol_Init (void)
/******************************************************************************
*                                                                             *
* Description:                                                                *
* This routine initializes the microcontroller to start the protocol and      *
* results unique starting conditions                                          *
*                                                                             *
* Parameters: none                                                            *
* Result:     none                                                            *
*                                                                             *
******************************************************************************/
{
   EA   = 0;

   TR0  = 0;		   /* stop timer 0 */
   TMOD &= 0xF0;
   TMOD |= 0x01;   /*timer 0 = 16 bit counter */
   TL0  = -30;     /* setup timer for immediate timeout */
   TH0  = -1;

   IT0  = 1;       /* INT0 = negative edge triggered */

   EX0  = 0;		
   ET0  = 0;

   PX0  = 1;		   /* high priority*/
   PT0  = 1;	     /* high priority*/

   TF0  = 0;
   IE0  = 0;

   EA   = 1;        /* enable all interrupts */
}


void Protocol_Stop (void)
/******************************************************************************
*                                                                             *
* Description:                                                                *
* This functions offers the possibility to stop the protocol at any time.     *
*                                                                             *
* Parameters:none 			                                 				      *
* Return:    none                                                             *
*                                                                             *                  
******************************************************************************/
{
   Protocol_State = P_STOP;
   EX0  = 0;		
   ET0  = 0;

   TF0  = 0;
   IE0  = 0;
#ifdef HTRC110
   SCLK=HIGH; SCLK=LOW;
#endif
}


void Send_HT_Bits (void)
/******************************************************************************
*                                                                             *
* Description:                                                                *
* Initializes and starts the transmission of bits via the HTRC110. N shall    *
* defined in the configuration pages of the HTRC110 before. N=0 is not 	      *
* allowed.                                                                    *
*                                            									      *
* Parameters: none                                                            *
* Return:     none 						                                          *
*                                                                             *
******************************************************************************/
{
#ifdef HTRC110
   SET_CONFIG_PAGE(CF_PAGE_2+THRESET+FREEZE0);

   WRITE_TAG();		           /*set HTRC110 to transparent mode*/
#endif
   IntVec = Send_HT_Bits_INT;   /* sets function call after interrupt*/

   Decoder_State = D_STOP;

   Bit_Count   = 0;

   DIN=LOW;                     /* Enable DIN pin for write pulses */

   TR0=0;
   if(TF0)
   {
      TL0=-30;
      TH0=-1;
   }

   EX0=0;
   TF0=0;
   ET0=1;
   TR0=1;
}



void Receive_HT_Bits (void)
/******************************************************************************
*                                                                             *
* Description:                                                                *
* Initializes the detection of coding scheme and polarity and of the decoder  *
*                                                                             *
* Parameters: none                                                            *
* Return:none                                                                 *
*                                                                             *
******************************************************************************/
{
#ifdef HTRC110
   HTRC110_wait(NO_200US);

   SET_CONFIG_PAGE(CF_PAGE_2+THRESET+FREEZE1+FREEZE0);

   HTRC110_wait(NO_250US);

   SET_CONFIG_PAGE(CF_PAGE_2);

   READ_TAG();		   /*set HTRC110 to transparent mode*/
#endif

   IntVec = Receive_HT_Bits_INT;

   Decoder_State = D_START;

   DOUT=HIGH;        /* Enable DOUT for data input */

   EX0=0;
   ET0=1;
   TR0=1;
}



void next_HT_state (void)
/******************************************************************************
*                                                                             *
* Description:                                                                *
* High level state machine of the HITAG2 protocol                             *
*                                                                             *
* Parameters: none                                                            *
* Return:     none                                                            *
*                                                                             *
******************************************************************************/
{
   switch (Protocol_State)
   {
      /* Start of protocol, send command bit stream */
      case P_START:
         Protocol_State = P_SEND_CMD;

         Protocol_Init();

         if( Cypher == CRYPTO  &&  HT_Command != HT_AUTHENT )
         {
            /* Encrypt command: */
            if (Crypt_Block( Byte_Addr, NBit ))
            {
              Decoder_State = C_TIMEOUT;
              Protocol_Stop();
              Exec_Protocol_Callback();
              return;
            }
         }

         Send_HT_Bits();    /* Prepare to transmit */
         return;


      /* Command has been sent, receive response from HITAG2  .... */
      case P_SEND_CMD:
         switch(HT_Command)
         {
            case HT_HALT:    /* ... the 10 bit command receipt */
               NBit= 10;
               Protocol_State = P_RECEIVE_HALT_RECEIPT;
               break;
            case HT_WRITE:   /* ... the 10 bit command receipt */
               NBit= 10;
               Protocol_State = P_RECEIVE_WRITE_RECEIPT;
               break;
            case HT_AUTHENT: /* ... the 32 bit transponder identifier */
               NBit= 32;
               Protocol_State = P_RECEIVE_IDENT;
               break;
            case HT_READ:    /* ... 32 bit data */
               NBit= 32;
               Protocol_State = P_RECEIVE_PAGE;
               break;
         }
         Exec_Protocol_Callback();

         Receive_HT_Bits();    /* Prepare for receive       */
         return;


/*******************************************************************
*       the mutual authentication.......                           *
*******************************************************************/

      /* Identifier received, transmit lock password now (plus */
      /* random number in CRYPTO mode)                         */
      case P_RECEIVE_IDENT:
         Protocol_State = P_SEND_PASSWORD;

         if (Cypher == CRYPTO)
         {
            /* Initialise HITAG2 crypto algorithm: */
            if (Crypt_Set_Ident( Byte_Addr-4 ))
            {
              Decoder_State = C_TIMEOUT;
              Protocol_Stop();
              Exec_Protocol_Callback();
              return;
            }

         }

         Exec_Protocol_Callback();
         if( Protocol_State != P_SEND_PASSWORD )
            return;   /* User abort in callback program! */

         NBit=32;     /* For PASSWORD mode: 32 bits to transmit */
         if (Cypher == CRYPTO)
         {
            /* Compute random number and ciphered lock password: */
            if (Crypt_Get_Rand_RWDPass( Byte_Addr ))
            {
              Decoder_State = C_TIMEOUT;
              Protocol_Stop();
              Exec_Protocol_Callback();
              return;
            }

            NBit=64;  /* CRYPTO mode : 64 bits to transmit */
         }

         Send_HT_Bits();    /* Prepare to transmit */
         return;


      /* Lock password has been transmitted, receive */
      /* transponder password now                    */
      case P_SEND_PASSWORD:
         Protocol_State = P_RECEIVE_PASSWORD;

         Exec_Protocol_Callback();

         NBit = 32;            /* Number of bits to receive */
         Receive_HT_Bits();    /* Prepare for receive       */
         return;


      /* Transponder password has been received, finish authentication */
      case P_RECEIVE_PASSWORD:
         Protocol_State = P_WAIT;

         if (Cypher == CRYPTO)
         {
            if (Crypt_Decipher_HT2Pass( Byte_Addr-4 ))
            {
              Decoder_State = C_TIMEOUT;
              Protocol_Stop();
              Exec_Protocol_Callback();
              return;
            }

         }

         IntVec         = Wait_End_INT;
         return;


/*******************************************************************
*     writing the transponder.......                               *
*******************************************************************/

      /* Write receipt was received, transmit data block to program */
      case P_RECEIVE_WRITE_RECEIPT:
         Protocol_State = P_SEND_PAGE;

         if( Cypher == CRYPTO)
         {
            /* Decrypt 10 bit write receipt: */
            if (Crypt_Block( Byte_Addr-2, 10 ))
            {
              Decoder_State = C_TIMEOUT;
              Protocol_Stop();
              Exec_Protocol_Callback();
              return;
            }

         }

         Exec_Protocol_Callback();
         if( Protocol_State != P_SEND_PAGE )
            return;   /* User abort in callback program! */

         if (Cypher == CRYPTO)
         {
            /* Encrypt 32 bit data block before transmission: */
            if (Crypt_Block( Byte_Addr, 32 ))
            {
              Decoder_State = C_TIMEOUT;
              Protocol_Stop();
              Exec_Protocol_Callback();
              return;
            }
         }

         NBit = 32;         /* Number of bits to transmit */
         Send_HT_Bits();    /* Prepare to transmit */
         return;


      /* Data block has been transmitted, finish protocol after */
      /* EEPROM programming time has elapsed                    */
      case P_SEND_PAGE:
         Protocol_State = P_WAIT;

         TR0 = 0;
         TH0 = (-(NO_T_WAIT_PROG+NO_T_WAIT_2)) / 256;
         TL0 = (-(NO_T_WAIT_PROG+NO_T_WAIT_2)) % 256;
         TR0 = 1;

         IntVec         = Wait_End_INT;
         return;


/*******************************************************************
*     reading the transponder......                                *
*******************************************************************/

      /* Data block has been received, finish protocol */
      case P_RECEIVE_PAGE:
         Protocol_State = P_WAIT;

         if (Cypher == CRYPTO)
         {
            /* Decrypt 32 bit received block: */
            if (Crypt_Block( Byte_Addr-4, 32 ))
            {
              Decoder_State = C_TIMEOUT;
              Protocol_Stop();
              Exec_Protocol_Callback();
              return;
            }

         }

         IntVec         = Wait_End_INT;
         return;


/*******************************************************************
*     halt command.......                                          *
*******************************************************************/

      /* Halt response has been received, finish protocol */
      case P_RECEIVE_HALT_RECEIPT:
         Protocol_State = P_WAIT;

         if( Cypher == CRYPTO)
         {
            /* Decrypt 10 bit halt receipt: */
            if (Crypt_Block( Byte_Addr-2, 10 ))
            {
              Decoder_State = C_TIMEOUT;
              Protocol_Stop();
              Exec_Protocol_Callback();
              return;
            }

         }

         IntVec         = Wait_End_INT;
         return;


/*******************************************************************
*     finishing the protocol.......                                *
*******************************************************************/

      case P_WAIT:
      case P_STOP:
         Protocol_Stop();
         Exec_Protocol_Callback();
         return;

   } /* end of switch */
} 	  /*end of next_HT_state()*/