/* smartkey.c  question and answer, compare strings     */
/* This program is for 16F84 Gold Card                  */

/*
SmartCard contact
             __ __ __
       +5V  |C1|   C5| Gnd
            |__|   __|
      MCLR  |C2|  |C6| 
            |__|  |__|
       OSC  |C3|  |C7| RB7/PGD I/O -><- Txd/Rxd half duplex 
            |__|  |__|
            |C4|  |C8|
            |__|__|__|

*/

/*
  SERIAL COMMUNICATION
  ============================
  One start bit, one stop bit, 8 data bit, no parity = 10 bit.
  Baudrate: 9600 baud => 104.167 usec. per bit.
  serial output PORTB.7  half duplex!
  serial input  PORTB.7  half duplex!
*/

#include "16F84.h"
#define MAX_STRING 16  /* string input max 15 characthers */
#pragma config |= 0x3ff1

/* Function prototypes                                   */
void initserial( void );
void putchar( char );
char getchar( void );
void string_out( const char * string ); 
void string_in( char * );
bit check_candidate( char * input_string, const char * candidate_string ); 
void delay( char );

void main( void)
{
   char i, c, d, charCount;
   char input_string[MAX_STRING]; /* 15 char buffer for input string */   
   bit compare;
   delay(50);  /* delay to stabilize power */

   initserial();

   string_in( &input_string[0] );

   /* Compare input and question text */
   compare = check_candidate( &input_string[0], "who is it?" );
   
   delay(150);     /* give the lock time to get ready */

   if(compare == 1)
     string_out("me, please open\r\n");  /* Observe '\r' */

   while(1) nop(); /* end of communication */
}

/********************
     FUNCTIONS
     =========
*********************/


void initserial( void ) /* initialise serialcom port */
{
   PORTB.7 = 1;
   TRISB.7 = 1;  /* input mode */
}


void putchar( char d_out )  /* sends one char */
{
   char bitCount, ti;
   TRISB.7 = 0; /* output mode */
   PORTB.7 = 0; /* set startbit */
   for ( bitCount = 10; bitCount > 0 ; bitCount-- )
        {
         /* 104 usec at 3,58 MHz (5+27*3-1+9=104) */  
         // ti = 27; do ; while( --ti > 0);
         /* 104 usec at 4 MHz (5+30*3-1+1+9=104)  */         
          ti = 30; do ; while( --ti > 0); nop();   
          Carry = 1;           /* stopbit                        */
          d_out = rr( d_out ); /* Rotate Right through Carry     */
          PORTB.7 = Carry;
        }
        nop2(); nop2();
   return; /* all done */
}


char getchar( void )  /* recieves one char */
{
   /* One start bit, one stop bit, 8 data bit, no parity = 10 bit. */
   /* Baudrate: 9600 baud => 104.167 usec. per bit.                */
   TRISB.7 = 1; /* set input mode */
   char d_in, bitCount, ti;
   while( PORTB.7 == 1 )  /* wait for startbit */ ;
   /* delay 1,5 bit is 156 usec                         */ 
   /* 156 usec is 156 op @ 4 MHz ( 5+47*3-1+2+9=156)    */
   ti = 47; do ; while( --ti > 0); nop2();  
   for( bitCount = 8; bitCount > 0 ; bitCount--)
       {
        Carry = PORTB.7;
        d_in = rr( d_in);  /* rotate carry */
        /* delay 1 bit is 104 usec                       */ 
        /* 104 usec is 104 op @ 4 MHz (5+30*3-1+1+9=104) */  
        ti = 30; do ; while( --ti > 0); nop();  
        }
   return d_in;
}

void string_in( char * input_string )
{
   char charCount, c;
   for( charCount = 0; ; charCount++ )
       {
         c = getchar( );     /* input 1 character             */
         input_string[charCount] = c;  /* store the character */
         //putchar( c );     /* don't echo the character      */
         if( (charCount == (MAX_STRING-1))||(c=='\r' )) /* end of input   */
           {
             input_string[charCount] = '\0';  /* add "end of string"      */
             return;
           }
       }
}


void string_out(const char * string)
{
  char i, k;
  for(i = 0 ; ; i++)
   {
     k = string[i];
     if( k == '\0') return;   /* found end of string */
     putchar(k); 
   }
  return;
}


bit check_candidate( char * input_string, const char * candidate_string )
{
   /* compares input buffer with the candidate string */
   char i, c, d;
   for(i=0; ; i++)
     {
       c = input_string[i];
       d = candidate_string[i];
       if(d != c ) return 0;       /* no match    */
         if( d == '\0' ) return 1; /* exact match */
     }
}

void delay( char millisec)
/* 
  Delays a multiple of 1 milliseconds at 4 MHz
  using the TMR0 timer 
*/
{
    OPTION = 2;  /* prescaler divide by 8        */
    do  {
        TMR0 = 0;
        while ( TMR0 < 125)   /* 125 * 8 = 1000  */
            ;
    } while ( -- millisec > 0);
}