/*  Filename     PKIT4.C
    Description  PKIT-4 Monitor Program
    Hardware     PKIT-4
    Compiler     CCS PCM C Complier V 3.173
    Engineer     Kriangsak B.
    Company      Sila Research Co.,Ltd. */

/********** SETUP & I/O **********/

#include <16f819.h>
#include <pkit4char.c>

//#fuses LP // Low power osc < 200 khz
//#fuses XT // Crystal osc <= 4mhz
//#fuses HS	// High speed Osc (> 4mhz)
//#fuses EC_IO	// External clock
#fuses INTRC_IO // Internal RC Osc, no CLKOUT
//#fuses INTRC	// Internal RC Osc
//#fuses RC_IO // Resistor/Capacitor Osc
//#fuses RC	// Resistor/Capacitor Osc with CLKOUT

//#fuses WDT // Watch Dog Timer
#fuses NOWDT // No Watch Dog Timer
#fuses PUT // Power Up Timer
//#fuses NOPUT // No Power Up Timer
//#fuses MCLR // Master Clear pin enabled
#fuses NOMCLR // Master Clear pin used for I/O
//#fuses BROWNOUT // Reset when brownout detected
#fuses NOBROWNOUT // No brownout reset
//#fuses LVP // Low Voltage Programming on B3
#fuses NOLVP // No low voltage prgming, B3 used for I/O
//#fuses CPD // Data EEPROM Code Protected
#fuses NOCPD // No EE protection
//#fuses WRT // Program Memory Write Protected
#fuses NOWRT // Program memory not write protected
//#fuses DEBUG // Debug mode for use with ICD
#fuses NODEBUG // No Debug mode for ICD
//#fuses CCPB2 // CCP1 input/output multiplexed with RB2
//#fuses CCPB3 // CCP1 input/output multiplexed with RB3
//#fuses PROTECT // Code protected from reads
#fuses NOPROTECT // Code not protected from reading

#use delay (clock=4000000)
#use rs232 (rcv=PIN_B0,baud=2400,bits=8,parity=n)

#byte OSCCON = 0x8F

#define CLK PIN_A0
#define STR PIN_A1
#define DATA PIN_A7
#define OE PIN_A6
#define COLA PIN_A2
#define COLB PIN_A3
#define COLC PIN_A4

#define RXD PIN_B0
#define DIP1 PIN_B4
#define DIP2 PIN_B5
#define DIP3 PIN_B6
#define DIP4 PIN_B7

#define BCD_A PIN_B1
#define BCD_B PIN_B3
#define BCD_C PIN_A5
#define BCD_D PIN_B2

/********** VARIABLE **********/

char DISBUF[8];
char MEMBUF[8];
char COMBUF[35];

/********** SUB FUNCTION **********/

char inbcd (void) {
    char x;
    x = input (BCD_D);
    x = (x << 1) | input (BCD_C);
    x = (x << 1) | input (BCD_B);
    x = (x << 1) | input (BCD_A);
    return (x);
}

char indip (void) {
    char x;
    x = input (DIP1);
    x = (x << 1) | input (DIP2);
    x = (x << 1) | input (DIP3);
    x = (x << 1) | input (DIP4);
    return (~x & 0xf);
}

void out595 (char x) {                      // out x to 74hc595
    char i;
    output_low (CLK);
    output_low (STR);
    for (i=0;i<=7;++i) {
        if (x & 0x1) output_high (DATA); else output_low (DATA);
        x >>= 1;
        output_high (CLK);
        output_low (CLK);
    }
    output_high (STR);
    output_low (STR);
}

char scan (char d) {
    int x;
    char i;
    while (d>0) {
        for (i=0;i<=7;i++) {
            if (i & 0x1) output_high (COLA); else output_low (COLA);      // out column
            if (i & 0x2) output_high (COLB); else output_low (COLB);
            if (i & 0x4) output_high (COLC); else output_low (COLC);
            out595 (DISBUF[i]);                                           // out row
            output_low (OE);
            x = 60;
            while (--x>0) {
                if (input (RXD)==0) {
                    output_high (OE);
                    return (1);                                           // exit (hot)
                }
            }
            output_high (OE);
        }
        d--;
    }
    return (0);                                                           // exit (normal)
}


void cclrm (void) {                              // clear membuf
    char i;
    for (i=0;i<=7;i++) MEMBUF[i] = 0;
}

char cloadm (char x) {                           // load char to membuf
    char i;                                      // return 0=err 5,8=char size
    if (x>=0x40 && x<=0x5a) {
        x = (x - 0x40) * 8;
        for (i=0;i<=7;i++) MEMBUF[i] = CHAGEN2[x++];
        return (5);
    }
    else if (x>=0x20 && x<=0x39) {
        x = (x - 0x20) * 8;
        for (i=0;i<=7;i++) MEMBUF[i] = CHAGEN1[x++];
        return (5);
    }
    else if (x>=0x10 && x<=0x17) {
        x = (x - 0x10) * 8;
        for (i=0;i<=7;i++) MEMBUF[i] = CHAGENX[x++];
        return (8);
    }
    else return (0);
}

char xconvert (char x) {                         // convert \x char to code
    if (x==0xd) return (0xd);
    if (x>=0x30 && x<=0x37) return (x - 0x20);
    else return (0);
}

void copy (void) {                               // load membuf to disbuf
    char i;
    for (i=0;i<=7;i++) DISBUF[i] = MEMBUF[i];
}

void center (void) {                             // adjust membuf (center)
    char i;
    for (i=0;i<=7;i++) MEMBUF[i] = MEMBUF[i] >> 2;
}

char speed (void) {                              // read speed from dip3,4
    char x;
    x = indip () & 0x3;
    if (x==0) return (17);
    else if (x==1) return (14);
    else if (x==2) return (11);
    else return (8);
}

void moveleft (char len) {                       // move membuf -> disbuf 1 char
    char i,j;
    for (j=0;j<=len;j++) {
        for (i=0;i<=7;i++) {
            DISBUF[i] <<= 1;
            if (MEMBUF[i] & 0x80) DISBUF[i] |= 0x01;
            MEMBUF[i] <<= 1;
        }
        scan (speed ());
    }
}

void actupx (void) {
    char i;
    for (i=0;i<=6;i++) DISBUF[i] = DISBUF[i+1];
}

void actup (void) {               // action up
    char i;
    actupx ();
    DISBUF[7] = 0;
    scan (speed ());
    for (i=0;i<=7;i++) {
        actupx ();
        DISBUF[7] = MEMBUF[i];
        scan (speed ());
    }
}

void actdownx (void) {
    char i;
    for (i=7;i>=1;i--) DISBUF[i] = DISBUF[i-1];
}

void actdown (void) {             // action down
    char i;
    actdownx ();
    DISBUF[0] = 0;
    scan (speed ());
    for (i=8;i>=1;i--) {
        actdownx ();
        DISBUF[0] = MEMBUF[i - 1];
        scan (speed ());
    }
}

void actleft (void) {             // action left
    char i,j;
    scan (speed ());
    for (j=0;j<=7;j++) {
        for (i=0;i<=7;i++) {
            DISBUF[i] <<= 1;
            if (MEMBUF[i] & 0x80) DISBUF[i] |= 0x01;
            MEMBUF[i] <<= 1;
        }
        scan (speed ());
    }
}

void actright (void) {            // action right
    char i,j;
    scan (speed ());
    for (j=0;j<=7;j++) {
        for (i=0;i<=7;i++) {
            DISBUF[i] >>= 1;
            if (MEMBUF[i] & 0x1) DISBUF[i] |= 0x80;
            MEMBUF[i] >>= 1;
        }
        scan (speed ());
    }
}

void actopen (void) {             // action open
    char i;
    scan (speed () * 2);
    DISBUF[3] = MEMBUF[3];
    DISBUF[4] = MEMBUF[4];
    scan (speed () * 2);
    DISBUF[2] = MEMBUF[2];
    DISBUF[5] = MEMBUF[5];
    scan (speed () * 2);
    DISBUF[1] = MEMBUF[1];
    DISBUF[6] = MEMBUF[6];
    scan (speed () * 2);
    DISBUF[0] = MEMBUF[0];
    DISBUF[7] = MEMBUF[7];
    scan (speed () * 2);
}

void actclose (void) {            // action close
    char i;
    scan (speed () * 2);
    DISBUF[0] = MEMBUF[0];
    DISBUF[7] = MEMBUF[7];
    scan (speed () * 2);
    DISBUF[1] = MEMBUF[1];
    DISBUF[6] = MEMBUF[6];
    scan (speed () * 2);
    DISBUF[2] = MEMBUF[2];
    DISBUF[5] = MEMBUF[5];
    scan (speed () * 2);
    DISBUF[3] = MEMBUF[3];
    DISBUF[4] = MEMBUF[4];
    scan (speed () * 2);
}

void flash (char x) {             // flash char & hang
    while (1) {
        cloadm (x);
        center ();
        copy ();
        scan (50);
        cclrm ();
        copy ();
        scan (50);
    }
}

/********** SUB FUNCTION **********/

void stest (void) {
    char i,x;
    while (1) {
        x = inbcd ();
        x = (x << 4) | indip ();
        DISBUF[3] = x;
        DISBUF[2] = x;
        DISBUF[1] = x;
        DISBUF[0] = x;
        x = ~x;
        DISBUF[7] = x;
        DISBUF[6] = x;
        DISBUF[5] = x;
        DISBUF[4] = x;
        scan (1);
    }
}

void command (void) {                            // read command from serial
    char a,i,f;
    i = 0;
    f = 0;
    while (1) {
        a = getc ();
        if (a==':') {                            // start
            i = 0;
            f = 1;
        }
        else if (a==0xd) {                       // end
            COMBUF[i] = a;
            return;
        }
        else {
            if (f && i<34) COMBUF[i++] = a;      // char
        }
    }
}

char checkaddr (char a) {                        // check addr with bcd-in
    char b,i;
    b = inbcd ();
    if (a==b) {
        for (i=0;i<=33;i++) COMBUF[i] = COMBUF[i+1];
        return (0);          // match
    }
    return (1);              // not match
}

void comwork (void) {                            // command working
    char a,i,c;
    i = 0;
    a = toupper (COMBUF[0]);
    if (a>='0' && a<='9') i = checkaddr (a & 0xf);
    if (a>='A' && a<='F') i = checkaddr ((a & 0xf) + 9);
    if (i==1) return;

    a = toupper (COMBUF[0]);
    if (a=='T') {                                // T command
        i = 1;
        moveleft (cloadm (' '));
        while (1) {
            a = toupper (COMBUF[i++]);
            if (a==0x5c) a = xconvert (COMBUF[i++]);
            if (a==0xd) {
                moveleft (cloadm (' '));
                moveleft (cloadm (' '));
                return;
            }
            if (a!=0) moveleft (cloadm (a));
        }
    }
    else if (a=='X') {                           // X command
        c = toupper (COMBUF[3]);                 // char
        if (c==0x5c) c = xconvert (COMBUF[4]);
        if (cloadm (c)==5) center ();

        a = toupper (COMBUF[1]);                 // action
        if (COMBUF[2]=='0') i = 1;
        else i = ((COMBUF[2] & 0x0f) + 1) * 25;  // delay
        switch (a) {
            case 'U': actup (); scan (i); break;
            case 'D': actdown (); scan (i); break;
            case 'L': actleft (); scan (i); break;
            case 'R': actright (); scan (i); break;
            case 'O': actopen (); scan (i); break;
            case 'C': actclose (); scan (i); break;
            case 'I': copy (); scan (i); break;
        }
    }
}

char comwrite (char addr) {                      // command write to eeprom
    char a,i;
    i = 0;
    while (1) {
        a = COMBUF[i++];
        write_eeprom (addr++,a);
        if (a==0xd) return (addr);
        if (addr==0) flash ('F');                // eeprom full (flash F)
    }
}

char comread (char addr) {                       // command read from eeprom
    char a,i;
    i = 0;
    while (1) {
        a = read_eeprom (addr++);
        if (a==0xff) flash ('N');                // no program
        COMBUF[i++] = a;
        if (a==0xd) return (addr);
    }
}

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

void start (void) {
    output_high (OE);                       // oe disable fisrt
    OSCCON = 0x60;                          // set int-osc 4 Mhz
    while ((OSCCON & 0x4)!=0x4);            // wait for clock stable
    cloadm (0x11);
    copy ();
    scan (100);
    cclrm ();
    copy ();
    port_b_pullups (true);
}

void bcd (void) {       // bcd mode
    char x,y,z;
    y = 0xff;
    while (1) {
        x = inbcd ();
        if (x!=y) {                         // de-bounce
            scan (25);
            if (x==inbcd ()) {
                z = x;                      // check bcd
                if (z==0) z = 'G';
                else if (z==11) z = 'A';
                else if (z==12) z = 'B';
                else if (z==13) z = 'C';
                else if (z==14) z = 'D';
                else if (z==15) z = ' ';
                else z = (z - 1) | 0x30;    // to ascii
                cloadm (z);                 // load
                center ();
                if (y==0xff) copy ();       // display
                else if (x>y) actdown ();
                else actup ();
            }
            y = x;
        }
        scan (5);
    }
}

void serial (void) {    // serial mode
    while (1) {
        if (scan (1)==1) {
            command ();
            if (COMBUF[0]=='Z' || COMBUF[0]=='z') stest ();
            comwork ();
        }
    }
}

void prog (void) {      // program mode
    char addr;
    addr = 0;
    while (1) {
        if (scan (1)==1) {
            command ();
            comwork ();
            addr = comwrite (addr);
            if (COMBUF[0]=='Z' || COMBUF[0]=='z') flash ('Z');      // end program
        }
    }
}

void run (void) {       // run mode
    char addr;
    addr = 0;
    while (1) {
        addr = comread (addr);
        comwork ();
        if (COMBUF[0]=='Z' || COMBUF[0]=='z') addr = 0;
    }
}

void main (void) {
    char x;
    start ();
    x = indip () & 0xc;
    if (x==0x0) bcd ();
    else if (x==0x4) serial ();
    else if (x==0x8) prog ();
    else run ();
}



