/* ------------------------------------------------------------------------ */
/*                                                                          */
/*                 Control Access System  'C' Source File                   */
/*                                                                          */
/* ------------------------------------------------------------------------ */
/*    Author:  Andrés Roldán Aranda   										        */
/* ------------------------------------------------------------------------ */


// Source control directives for the C-51 Compiler
#pragma ROM (LARGE)    //   The ROM directive is used to determine the size 
								// of the program memory. The ROM directive effects 
 	  	  						// the codind of the jump instructions.
 	  	  		
#pragma small          //   This directive control de selection of the memory
								// model to be implemented. 
 	  	  						// SMALL: All variables and local data segments of 
								// functions and procedures are defined to reside in the 
 	  	  						// internal data memory of the 8051 system.
 	  	  		            // Thus the access to data objects is very efficient.
 	  	  	             	// A disadvantage of this model is the limited address
 	  	  	               // space.
 	  	  	               
#pragma ot(5,SIZE)     // The OPTIMIZE directive sets the optimizing level.
								// A highger optimizing level contains each proceding 
 	  	  						// lower optimizing level.
 	  	  		            // Opt=5
 	  	  	             	//  Global Common Subexpresion-elimination:
 	  	  	             	//   Identical subexpressions within a function are 
 	  	  	               //   calculated only once,  when possible. The intermediate
 	  	  	               //   results are stored in a register and used instead of 
 	  	  	               //   a new calculation.
 	  	  	               //  Simple Loop Optimizing:
 	  	  	               //   Program loops that fill a memory range with a
 	  	  	               //   constant are converted an optimized in the runtime
 	  	  	               //   as a result.
 	  	  	               // SIZE.
 	  	  	               //  Optimization emphasis is placed in code size.
 	  	  	               
#include <reg52.h>        // 8052 register definition
#include "def.h"          // HW application register definition

#define TIMER0_COUNT 0x0003    // Timer 0 load value
                               //(10000h -((12.000.000 Hz / (12*Freq))-17 ))
#define NUMdeDIG 4        // Code digits number

#define ON 0
#define OFF 1

//*************************** Global Variables *************************** 

unsigned char APIL=1,LOC;    //APIL=available numeric passwords 
                             //LOC EEPROM auxiliary password pointer

char secuencia[NUMdeDIG];    //Entered Keypad password 

unsigned long int clave;     //Auxiliary var. used in BCD-entered code conversion

int clave_aux;               //Variables used when an access code is stored in
char clave_aux1,clave_aux2;  //EEPROM
int LSB;                     
char MSB;                  

unsigned int time,aux;   //Dalay signaling var.  Used in TIMER 0 interruption

bit abit=0,modo_sup;     //Supervisor mode signaling se usan para se¤alizar el modo supervisor

bit alarm_puerta=ON;    //An alarm is set if the door is opened for too much.


//*************************** Extern Functions *************************** 

//From keypad module
extern scan_teclado( void );   //Returns the key pressed
extern enviar_columna( unsigned char dato );   // Used in supervisor mode test

//From EEPROM module
extern unsigned char mChip24LC04B_Read( unsigned char Address );  
extern unsigned char mChip24LC04B_Write(unsigned char Address, unsigned char Dato);
                                       


                    /************************
                    *   TIMER 0 Setup       *
                    ************************/

void arranque_timer(void) 
{
 EA=0;                          // Disable all interrupt.
 TR0=0;                         // Paramos el tim
 TMOD &= ~0x0F;                  // Borramos los bits del timer0
 TMOD |=0x01;                   // Ponemos el timer0 en contador de 16 bits
 TL0=(TIMER0_COUNT & 0x00FF);
 TH0=(TIMER0_COUNT >> 8);
 PT0=0;                         // Ponemos baja prioridad al timer0
 ET0=1;                         // Habilitamos la posibilid de int_timer0 
 TR0=1;                         // Arrancamos el timer0
 EA=1;                          // Habilitamos interrupciones
} 


                  /*****************************         
                  *    TIMER 0   INTER.        *               
                  *****************************/

static void timer0_isr (void) interrupt 1 using 2
{
 TR0=0;                              // Stop timer 0
 TL0= TL0 + (TIMER0_COUNT & 0x00FF); //Reload timer 0 LSB
 TH0= TH0 + (TIMER0_COUNT >> 8); 	//Reload timer 0 LSB
 TR0=1;                            // Start Timer 0 

 time++;  

 if((modo_sup) & ((time%5)==0))
  {
   LED_Yellow=abit;   //Now supervisor mode is active
   LED_Green=abit;   // LEDS are blinking
   LED_Red=abit;
   abit=~abit;
  }
}

                 /*********************
                 *  Delay procedure   *
                 *********************/

void delay(unsigned int retardo)
{
 aux=time;
 while(time<aux+retardo);
}

                   /********************
                   * Door Opened Alarm *
                   ********************/
void puerta_abierta()
{                                     
    unsigned char tiempo_espera=0;    
    while(!Magnetic_Sensor)                        
   {
     tiempo_espera++;                 
     delay(10);                       
     if(tiempo_espera>20)
    {
      alarm_puerta=OFF;
      break;
      }//if
     }//while
}

             /**********************************
             *   Steady state conditions setup * 
             *      in normal mode operation   *   
             **********************************/

void inicializar_sistema(void)
{

  LED_Yellow=ON;                       // LED_Yellow=ON
  LED_Green=OFF;                       // LED_Green=OFF
  LED_Red=OFF;                         // LED_Red=OFF

  Door_opener_solenoid=OFF;            // Door opener solenoid=OFF
  Buzzer=OFF;                          // Buzzer=OFF

}

                 /*********************               
                 *  NEW EEPROM TEST   *               
                 *********************/

bit test_actualizacion_eeprom()    // If keys (#,*,8) are pressed
{                                  // all access codes are deleted
												// this is usefull when a new EPPROM
												// is used.
  aux=time; 
  while(time<aux+31)          
 {                            
   enviar_columna(1);     
   if (FILA1 & FILA2 & FILA3 & !FILA4)    // Is '*' key pressed ?
    {
     enviar_columna(2);         
     if (FILA1 & FILA2 & !FILA3 & FILA4)  // Is '8' key pressed ?
      {
       enviar_columna(3);     
       if (FILA1 & FILA2 & FILA3 & !FILA4)// Is '#' key pressed ?
       
       return(1);             // Return 1 if keys (#,*,8) are pressed
      }   
    }
   return(0);              // Return 0 if keys (#,*,8) are not pressed
 }                
}


                 /********************               
                 *  Supervisor mode  *               
                 *       test        *               
                 ********************/

bit test_modo_supervisor()         // If keys (#,*,5) are pressed
{                                  // enter supervisor mode
												// This is usefull for enterin and deleting
												// access codes.
  aux=time; 
  while(time<aux+31)
 {                  
   enviar_columna(1);
   if (FILA1 & FILA2 & FILA3 & !FILA4)    // Is '*' key pressed ?
    {
     enviar_columna(2); 						 // Is '5' key pressed ?
     if (FILA1 & !FILA2 & FILA3 & FILA4)
      {
       enviar_columna(3); 					 // Is '#' key pressed ?
       if (FILA1 & FILA2 & FILA3 & !FILA4)        
       return(1);              // Return 1 if keys (#,*,5) are pressed      
      }                       
    }
   return(0);                  // Return 1 if keys (#,*,5) are not pressed      
 }                
}

                      /**************                     
                      *  POW = 10^  *
                      *  function   *
                      **************/

unsigned int potencia(unsigned char n)
{
  unsigned char m;
  unsigned int p=1;
  for(m=0;m<n;m++)
  p=10*p;
  return(p);                 //Return (10^n)
}

	       /****************************************              
	       *  Read a number sequence from keypad   *
	       ****************************************/

bit leer_secuencia()         //Reads a number sequence of NUMdeDIG digits,
                             //store it in secuencia[NUMdeDIG],
                             //converts it to BCD format,
                             //store the sequence in "clave" var.
{
          char N=0,tecla,i;          
          aux=time;
          while (time<aux+100)        //Wait for a moment to intoduce the sequence 
    { 
          if(!Magnetic_Sensor)        //If the door is opened exit
          return 0;                   //set the alarm ON
            switch (tecla=scan_teclado())
     {
	     case 0:
	     case 1:
	     case 2:
	     case 3:
	     case 4:
	     case 5:
	     case 6:
	     case 7:
	     case 8:
	     case 9:
	     case 0x10:
             case 0x11:
                       while (tecla==scan_teclado()); //Wait until the key us unpressed
                       secuencia[N]=tecla;            
                       N++;                           
                       Buzzer=ON;                     //The buzzer is on for a moment
                       delay(2);                      //to confirm key pressed 
                       Buzzer=OFF;
                       if(N==NUMdeDIG)     //If the sequence is complete
                       {                   //convert it to BCD and store it in 
                         clave=0;          //"clave" var.
                         for(i=0;i<N;i++)  
                         clave=(clave+((secuencia[i])*(potencia(N-1-i))));                        
                         return(1);        //Complete sequence detected
                        }
		       break;
             case 0x40:                    //repeat if no key is pressed
                       if(N<NUMdeDIG)      //and no time out  
                       break;              
	    }
	}
          return(0);       //No comprete sequence has been detected
  }                      


		 /*******************************                 
		 *     Code = Access Code ?     *
 	 	 *******************************/

bit comprobar_acceso()
{
  if(NUMdeDIG<=4)                   //If access code has 4 digits
 {
   clave_aux=(int)clave;            
   clave_aux1=(clave_aux & 0x00FF); //Access code LSB
   clave_aux2=(clave_aux >> 8);     //Access code MSB

                for(LOC=1;LOC<APIL;LOC++)   //Find access code in EEPROM 
               {                             
                                             
                 if(mChip24LC04B_Read(LOC)==clave_aux1) //Compare LSB
                 {                                        
                  LOC++;
                  if(mChip24LC04B_Read(LOC)==clave_aux2) //Compare MSB
                  return(1);            //Code = Access code (code is in memory)
                  }
                  LOC++;            
                }                   
                return(0);              //Code != Access code (code isn´t in memory)
  }
  if(NUMdeDIG>4)                    //If access code has more than 4 digits
 {
   LSB=(clave & 0x0000FFFF);        // The same as before
   MSB=(clave >> 16);               
   clave_aux1=(LSB & 0x00FF);       
   clave_aux2=(LSB >> 8);
 
                 for(LOC=1;LOC<APIL;LOC++)
                {
                  if(mChip24LC04B_Read(LOC)==clave_aux1)  
                 {                                        
                   LOC++;                 
                   if(mChip24LC04B_Read(LOC)==clave_aux2) 
                   {
                    LOC++;
                    if(mChip24LC04B_Read(LOC)==MSB) 
                    return(1);                      
                    }
                   LOC++;          
                  }                
                  LOC+=2;       
                 }                 
                 return(0);        
  }
}

		 /*******************************              
		 *  Update a new access code    *     
		 *******************************/

bit actualizacion()    //After code in entered, '#' key must be pressed to update
{                      //Updated access codes are stored in EEPROM

  if(NUMdeDIG<=4)       //If access code has 4 digits
 {
   clave_aux=(int)clave;                 
   clave_aux1=(clave_aux & 0x00FF); //Access code LSB    
   clave_aux2=(clave_aux >> 8);     //Access code MSB
   if(mChip24LC04B_Write(APIL,clave_aux1))     //If Access code LSB is written
   															// in EEPROM whit no errors
  {                                            // APIL is incremented.
    APIL++;                                    
    if(mChip24LC04B_Write(APIL,clave_aux2))    
    {                                          
     APIL++;                                   
     return 1;                           
     }
   }
   return 0;                             //No update confitmation
  }
  if(NUMdeDIG>4)                         //If access code has more than 4 digits 
 {                                       
   LSB=(clave & 0x0000FFFF);             // The same as before
   MSB=(clave >> 16);                    
   clave_aux1=(LSB & 0x00FF);
   clave_aux2=(LSB >> 8);
   if(mChip24LC04B_Write(APIL,clave_aux1)) 
  {                       
    APIL++;
    if(mChip24LC04B_Write(APIL,clave_aux2))
   {
     APIL++;             
     if(mChip24LC04B_Write(APIL,MSB))
    {
     APIL++;
     return 1;            
     }
    }                     
   }                      
   return 0;              
  }
}

        /************************                   
		   * Delete an access code *                 
		   ************************/

bit anulacion()       //After code in entered, '*' key must be pressed to delete
{           
   unsigned int D;
   if(comprobar_acceso())  //Test if code==Access Code ?
  {                        //LOC=Code memory locaton
    if(NUMdeDIG<=4)        //If access code has 4 digits
   {                       //Remove code and order the access codes in EEPROM
     for(D=LOC;D<APIL;D++)
    {
      D++;
      clave_aux1=mChip24LC04B_Read(D);
      D++;
      clave_aux2=mChip24LC04B_Read(D);
      D-=3;
      if(mChip24LC04B_Write(D,clave_aux1))
     {
       D++;
       if(mChip24LC04B_Write(D,clave_aux2))
       D++;
       }//if
      }//for
     APIL-=2;                     
     return 1;                    //Code is deleted
     }//if                        
    if(NUMdeDIG>4)                //If access code has more than 4 digits 
   {
     for(D=LOC;D<APIL;D++)               // The same as before
    {                            
     D++;
     clave_aux1=mChip24LC04B_Read(D);
     D++;
     clave_aux2=mChip24LC04B_Read(D);
     D++;
     MSB=mChip24LC04B_Read(D);
     D-=5;
     if(mChip24LC04B_Write(D,clave_aux1))
    {
      D++;
      if(mChip24LC04B_Write(D,clave_aux2))
     {
       D++;
       if(mChip24LC04B_Write(D,MSB))
       D+=2;
       }//if
      }//if
     }//for
     APIL-=3;                     
     return 1;                    
    }//if                         
   }//if                          
   return 0;                      //Code is not deleted
 }                                

               /****************************************************                        
               * Opration  update = Call(Update a new access code) *
               *           delete = Call(Delete an access code)    *
               ****************************************************/

bit operacion()
{
   aux=time;
   while(time<aux+50)             //Wait until operation is selected
  {                               //'#' updates & '*' deletes
    switch(scan_teclado())
    {
      case 0x11:
                while(scan_teclado()==0x11); //wait until '#' key is unpressed
                modo_sup=ON;
                if(actualizacion())     //if update is OK
               {
                Buzzer=ON;
                LED_Yellow=OFF;
                LED_Green=ON;                      //Signal update OK
                LED_Red=OFF;
                delay(7);      
                Buzzer=OFF;               
                return 1;                    //Confirm Update OK
                }
                break;
      case 0x10:
                while(scan_teclado()==0x10); //wait until '*' key is unpressed 
                modo_sup=ON;
                if(anulacion())          //if delete is OK
               {
                Buzzer=ON;
                LED_Yellow=OFF;
                LED_Red=ON;                       //Signal delete OK
                LED_Green=OFF;
                delay(7);       
                Buzzer=OFF;               
                return 1;                    //Confirm Delete OK
                }
                break;
     }//switch
   }//while
 return 0;                                   //no se confirma la operaci˘n
}

		    /**********************                    
		    *   Supervisor Mode   *                    
		    **********************/

void modo_superv()   // Update or delete access code
{

   LED_Yellow=OFF;           
   Buzzer=ON;
   delay(5);         //Buzzer ON to show sopervisor mode
   Buzzer=OFF;
   delay(20);        //Wait until supervisor mode keys are unpressed

   time=0;
   while(time<150)
  {
     modo_sup=1;
     if(leer_secuencia())        //Read input sequence 
    {                          
     time=0;
       if(operacion())           //If update or delete is done 
       time=0;                   //set time out for code entry =0
     }    
   }
     modo_sup=ON;
}

                 /*******
                 * MAIN *
                 *******/
main()
{               
               inicializar_sistema();
               arranque_timer();
               if(test_actualizacion_eeprom())    //If '#,8,*' keys are pressed, erase EEPROM
              {               
                if(mChip24LC04B_Write(0,1))    //  APIL=1
                {                              // If EEPROM erase is OK
  					LED_Yellow=OFF; 
						LED_Green=OFF; 
						LED_Red=ON; 
					   Buzzer=ON;
					   delay(10);         //Buzzer 
					   Buzzer=OFF;
 	  	   			LED_Red=OFF; 
 	  	   		  } 
 	  	   		  else  // EEPROM erase is not OK 
 	  	   	     {
						LED_Yellow=OFF; 
						LED_Green=ON; 
						LED_Red=ON; 
					   delay(10);  
 	  	   			LED_Green=OFF; 
						LED_Red=OFF;
                }
					  delay(20);        
					}
               if(test_modo_supervisor())   //If '#,5,*' keys are pressed, enter supervisor mode
              {               
                APIL=(mChip24LC04B_Read(0));   //Read number of stored access codes in EEPROM
                modo_superv();                 
                if(mChip24LC04B_Write(0,APIL)) //Write update number of stored access codes in EEPROM
                inicializar_sistema();         // Init system
                }                              
       while(1)
    {
              while(!Magnetic_Sensor)    //While door is opened
             {                           
               LED_Yellow=OFF;                   
               LED_Green=ON;              
               if(!alarm_puerta)    //If alarm is not set
               puerta_abierta();    
               if(Magnetic_Sensor)  
               break;               
               Buzzer=abit;         
               delay(8);           
               Buzzer=OFF;         
               delay(25);          
               abit=~abit;         
              }                    
               alarm_puerta=ON;      
               LED_Yellow=ON;                   //If door is closed
               LED_Green=OFF;                   //set alarm off and wait for a code entry
               if(leer_secuencia())             
              {
               APIL=(mChip24LC04B_Read(0));     //Read APIL (number of stored access codes in EEPROM)
               if(comprobar_acceso())           //Check code
	             {
                Door_opener_solenoid=ON;       //If code=access code open the door
                LED_Green=ON;                  
                delay(10);
                Door_opener_solenoid=OFF;      
                delay(20);                      //Show door opened
                LED_Green=OFF;                  
	             }
               else                             // Code != access code open the door
               {                                
		           LED_Red=ON;
                Buzzer=ON;
                delay(10);                      //Show access code incorrect
                LED_Red=OFF;                    //Deny the entry
                Buzzer=OFF;
	       }
           }
       }
   }

/* ------------------------------------------------------------------------ */
/*    Author:  Andrés Roldán Aranda   										        */
/*    Place:   Huelva 11-12-99						                             */
/*    XTAL:    12 MHz	         					                             */
/* ------------------------------------------------------------------------ */

