/*  Filename     pkit8.c
    Description  PKIT-8 General Code-Key
    Hardware     PKIT-8
    Compiler     CCS PCW C Complier V3.28
    Engineer     Kriangsak B.
    Company      Sila Research Co.,Ltd. */

#include <16f819.h>
#fuses INTRC_IO,PUT,NOWDT,NOMCLR,NOBROWNOUT,NOCPD,NOLVP,NOWRT,NODEBUG,NOPROTECT

#use delay (clock=4000000)
#byte OSCCON = 0x8F
#use rs232 (rcv=PIN_B4,xmit=PIN_B5,baud=9600,bits=8,parity=n)

#define  DIP2      PIN_A0
#define  DIP1      PIN_A1
#define  KEYC2     PIN_A2
#define  KEYC1     PIN_A3
#define  KEYC0     PIN_A4
#define  KEYR0     PIN_A5
#define  RELAY     PIN_A6
#define  DIP3      PIN_A7

#define  KEYR1     PIN_B0
#define  KEYR2     PIN_B1
#define  KEYR3     PIN_B2
#define  SBIT      PIN_B3
#define  D485      PIN_B6
#define  LED       PIN_B7

/********** WORKING RAM **********/

char     PASS[4];            // password
char     KEY[4];             // key input
int32    AUTOLK;             // auto lock counter
int1     KFAG;               // key flag
int1     PULF;               // pulse flag

/********** BASIC FUNCTION **********/

void sound (char freq,signed int16 time) {       // Sound Generate
    unsigned char i;
    while (time>0) {
        output_low (SBIT);                       // out signal low
        for (i=1;i<=freq;i++)
            time--;
        output_high (SBIT);                      // out signal high
        for (i=1;i<=freq;i++)
            time--;
    }
}

void beepk (void) {sound (50,500);}
void beeph (void) {sound (12,20000);}
void beepl (void) {sound (80,30000);}

void flash (void) {
    output_low (LED);
    delay_ms (400);
    output_high (LED);
    delay_ms (400);
}

void flashx (void) {
    output_low (LED);
    delay_ms (150);
    output_high (LED);
    delay_ms (150);
}

char const KEYTAB[12] = {              // key table
    0xe1,0x70,0x71,0x72,
    0xb0,0xb1,0xb2,0xd0,
    0xd1,0xd2,0xe0,0xe2};

char gkey (void) {                     // get key
    char i,j,x;                        // out=0xff nothing out=0-9,a,b key press
    for (i=0;i<=2;i++) {
        switch (i) {
            case 0: output_high (KEYC2); output_high (KEYC1); output_low (KEYC0); break;
            case 1: output_high (KEYC2); output_low (KEYC1); output_high (KEYC0); break;
            case 2: output_low (KEYC2); output_high (KEYC1); output_high (KEYC0); break;
        }
        x = input (KEYR3);
        x = (x << 1) | input (KEYR2);
        x = (x << 1) | input (KEYR1);
        x = (x << 1) | input (KEYR0);
        x = (x << 4) & 0xf0;
        if (x!=0xf0) {
            if (KFAG==0) {
                delay_ms (50);
                KFAG = 1;
                output_low (LED);
                beepk ();
                output_high (LED);
                x = x | i;
                for (j=0;j<=11;j++) {
                    if (x==KEYTAB[j]) return (j);
                }
                return (0xff);
            }
            else return (0xff);
        }
    }
    KFAG = 0;
    return (0xff);
}

/********** MAIN FUNCTION **********/

void run_lock_relay (void) {
    char x;
    x = input (DIP1);
    x = (x << 1) | input (DIP2);
    x = ~x & 0x03;
    if (x==0) output_low (RELAY);
    else if (x==1) output_high (RELAY);
    else if (x==2) {
        output_low (RELAY);
        PULF = 1;
    }
    else output_high (RELAY);
}

void run_lock (void) {
    delay_ms (400);
    run_lock_relay ();
    beeph ();
    delay_ms (400);
    if (PULF) {
        PULF = 0;
        delay_ms (600);
        output_high (RELAY);
    }
    flash ();
}

void run_unlock_relay (void) {
    char x;
    x = input (DIP1);
    x = (x << 1) | input (DIP2);
    x = ~x & 0x03;
    if (x==0) output_high (RELAY);
    else if (x==1) output_low (RELAY);
    else if (x==2) {
        output_low (RELAY);
        PULF = 1;
    }
    else {
        output_low (RELAY);
        AUTOLK = 17000;                // auto lock in 5 second
    }
}

void run_unlock (void) {
    delay_ms (400);
    run_unlock_relay ();
    beeph ();
    delay_ms (400);
    if (PULF) {
        PULF = 0;
        delay_ms (600);
        output_high (RELAY);
    }
    flash ();
    flash ();
}

void error (void) {
    delay_ms (400);
    beepl ();
    output_low (LED);
    delay_ms (1500);
    output_high (LED);
}

void wait (void) {
    int16 a;
    delay_ms (400);
    a = 5 * 600;                            // 10 minute
    while (a-->0) {
        output_low (LED);
        delay_ms (75);
        output_high (LED);
        delay_ms (125);
    }
}

void getpass (void) {
    PASS[0] = read_eeprom (0);              // read password to var.
    if (PASS[0]==0xff) PASS[0] = 1;
    PASS[1] = read_eeprom (1);
    if (PASS[1]==0xff) PASS[1] = 2;
    PASS[2] = read_eeprom (2);
    if (PASS[2]==0xff) PASS[2] = 3;
    PASS[3] = read_eeprom (3);
    if (PASS[3]==0xff) PASS[3] = 4;
}

void setpass (void) {                      // set password to eeprom
    write_eeprom (0,KEY[0]);
    write_eeprom (1,KEY[1]);
    write_eeprom (2,KEY[2]);
    write_eeprom (3,KEY[3]);
    getpass ();
}

void start (void) {
    OSCCON = 0x60;                          // set int-osc 4 Mhz
    while ((OSCCON & 0x4)!=0x4);            // wait for clock stable
    output_low (D485);
    output_high (KEYR0);
    output_high (KEYR1);
    output_high (KEYR2);
    output_high (KEYR3);
    delay_ms (400);
    flashx ();
    flashx ();
    delay_ms (400);
}

void main (void) {
    char x,c,w;
    int32 d;
    int1 lock,f;

    start ();
    if (input (DIP3)==0) {                  // default password 1234
        delay_ms (400);
        write_eeprom (0,1);
        write_eeprom (1,2);
        write_eeprom (2,3);
        write_eeprom (3,4);
        for (x=40;x>=10;x--) sound (x,1000);
        delay_ms (400);
    }

    getpass ();                   // init variable
    KEY[0] = PASS[0];
    KEY[1] = PASS[1];
    KEY[2] = PASS[2];
    KEY[3] = PASS[3];
    PULF = 0;
    c = 0;                        // key counter
    w = 0;                        // wrong counter
    d = 0;                        // flash delay
    f = 0;                        // flash flag

    x = input (DIP1);             // lock first except pulse mode
    x = (x << 1) | input (DIP2);
    x = ~x & 0x03;
    if (x!=2) run_lock ();
    lock = 1;

    while (1) {
        if (lock==1 && c==4) {                        // **** compare password & work ****
            c = 0;
            if (KEY[0]==PASS[0] &&                    // unlock (password ok)
                KEY[1]==PASS[1] &&
                KEY[2]==PASS[2] &&
                KEY[3]==PASS[3]) {
                run_unlock ();
                lock = 0;
            }
            else {                                    // password error
                error ();
                w++;
                if (w>=3) {                           // wait (error=3)
                    wait ();
                    w = 0;
                }
            }
        }

        x = gkey ();                                  // **** get key ****
        if (x!=0xff) {
            d = 0;
            f = 0;
            if (x==0xa) c = 0;                        // cancel
            else if (x==0xb && lock==0) {             // lock
                if (c==4) setpass ();                 // set password
                run_lock ();
                lock = 1;
                c = 0;
                w = 0;
            }
            else if (x!=0xb) {                        // input key
                if (c<=3) KEY[c++] = x;
            }
        }

        if (lock==1) {                                // **** lock flash (5 second) ****
            d++;
            if (f==0 && d>=17000) {                   // to bright
                d = 0;
                f = 1;
                output_low (LED);
            }
            else if (f==1 && d>=300) {                // to dark
                d = 0;
                f = 0;
                output_high (LED);
            }
        }

        if (AUTOLK>0) {                               // **** auto lock delay ****
            AUTOLK--;
            if (AUTOLK==0) {
                run_lock ();
                lock = 1;
                c = 0;
                w = 0;
                d = 0;
                f = 0;
            }
        }
    }
}

