/*  Filename     VE54.C v1.0 ???
    Description  V-E54 QC Program
    Hardware     V-E54
    MCU			 82E54AE (Speed x12)
    Clock        11.0592 Mhz 
    Compiler     Keil PK51 v7.10
    Engineer     Kriangsak B. 
    Company      Sila Research Co.,Ltd. 
*/

#include <reg52.h>
#include <absacc.h>
#include <assert.h>
#include <ctype.h>
#include <intrins.h>
#include <math.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define  MAXBUF    8         // maximun for combuf (not include ':' & 0xd)

/********** I/O PORT **********/

sbit     P10 	   = P1^0;
sbit     P11 	   = P1^1;
sbit     P12 	   = P1^2;
sbit     P13 	   = P1^3;
sbit     P14 	   = P1^4;
sbit     P15 	   = P1^5;
sbit     P16 	   = P1^6;
sbit     P17 	   = P1^7;

sbit     MCPSDI    = P2^0;
sbit     MCPSCK    = P2^2;
sbit     MCPCS1    = P2^3;   // mcp4921 D/A (ch 1)
sbit     MCPCS2    = P2^4;   // mcp4921 D/A (ch 2)    

sbit     UDIN      = P2^0;   // max3100 uart
sbit     UDOUT     = P2^1;
sbit     UCLK      = P2^2;
sbit     UCS       = P2^5;

sbit     IPSCL	   = P2^6;
sbit     IPSDA     = P2^7;

sbit     KEY1      = P3^2;
sbit     KEY2      = P3^3;
sbit     D485      = P3^4;
sbit     SOUNDB    = P3^5;
sbit     P37 	   = P3^7;

/********** INT-RAM WORKING AREA **********/

unsigned int            SPEEDM;             // baud-rate memory
unsigned char           COMBUF[MAXBUF+1];   // communication buffer
unsigned char           COMINX;             // COMBUF index
unsigned char           TIMBUF[8];          // ss,mm,hh,ww,dd,mm,yy,cc 
unsigned char           STRBUF[20];         // string buffer

         bit            TXOK;               // tx flag
         bit            RXOK;               // rx command ready flag
         bit            SCOMF;              // start command flag
		 bit            ACOMF;              // ascii command flag

unsigned char bdata     BITMAP;
sbit                    B0 = BITMAP^0;
sbit                    B1 = BITMAP^1;
sbit                    B2 = BITMAP^2;
sbit                    B3 = BITMAP^3;
sbit                    B4 = BITMAP^4;
sbit                    B5 = BITMAP^5;
sbit                    B6 = BITMAP^6;
sbit                    B7 = BITMAP^7;

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

void dmsec (unsigned int count) {           // mSec Delay
    unsigned int i;                         // for Keil PK51 (Speed x 12) 82E54AE2
    while (count) {
        i = 850; while (i>0) i--;
        count--;
    }
}

void sound (unsigned char freq,long time) {      // Sound Generate (Speed x 12)
    unsigned char i;
    while (time>0) {
        SOUNDB = 0;                              // out signal low
        for (i=1;i<=freq;i++) {
		    time--;
		    time++;
		    time--;
		}
        SOUNDB = 1;                              // out signal high
        for (i=1;i<=freq;i++) {
		    time--;
		    time++;
		    time--;
		}
    }
}

unsigned int chks (void) {
    unsigned int c,addr;
    bit countflag;
    countflag = 0;
    c = 0;
    for (addr=0x17ff;addr>0;addr--) {       // find checksum (auto 6K)

        if (countflag==0 && CBYTE[addr]!=0xff) countflag = 1;
        if (countflag) c = c + CBYTE[addr];
    }
    c = c + CBYTE[0];
    return (c);
}

void ipdel (void) {                    // I2C delay 
    unsigned char i;
    for (i=0;i<=9;i++) {
        _nop_ ();
        _nop_ ();
        _nop_ ();
        _nop_ ();
        _nop_ ();
        _nop_ ();
        _nop_ ();
        _nop_ ();
    }
}

void ipchigh (void) {                  // I2C clock high 
    IPSCL = 1;
    ipdel ();
}

void ipclow (void) {                   // I2C clock low 
    IPSCL = 0;
    ipdel ();
}

void ipstart (void) {                  // start condition 
    IPSDA = 1;
    IPSCL = 1;
    IPSDA = 0;
    ipdel ();
    IPSCL = 0;
    IPSDA = 1;
}
                                        
void ipstop (void) {                   // stop condition 
    IPSDA = 0;
    IPSCL = 1;
    ipdel ();
    IPSDA = 1;
}

bit ipwrbyte (unsigned dat) {          // write one byte 
    unsigned char i;                   // return 0 = ok 
    bit outbit;                        // return 1 = error 
    for (i=1;i<=8;i++) {
        outbit = dat & 0x80;
        IPSDA = outbit;
        dat = dat << 1;
        ipchigh ();
        ipclow ();
    }
    IPSDA = 1;
    ipchigh ();
    outbit = IPSDA;
    ipclow ();
    return (outbit);
}

unsigned char iprdbyte () {            // read one byte (last byte for ds1307) 
    unsigned char i,dat;              
    bit inbit;
    dat = 0;
    for (i=1;i<=8;i++) {
        ipchigh ();
        inbit = IPSDA;
        dat = dat << 1;
        dat = dat | inbit;
        ipclow ();
    }
    IPSDA = 1;
    ipchigh ();
    ipclow ();
    return (dat);
}

unsigned char iprdbytez () {           // read one byte ack=0 for DS1307 
    unsigned char i,dat;         
    bit inbit;
    dat = 0;
    for (i=1;i<=8;i++) {
        ipchigh ();
        inbit = IPSDA;
        dat = dat << 1;
        dat = dat | inbit;
        ipclow ();
    }
    IPSDA = 0;
    ipchigh ();
    ipclow ();
    IPSDA = 1;
    return (dat);
}

void ipwrep (unsigned int addr,unsigned char dat) {        // write 24lcxx (8 block) 
    unsigned char x;
    x = ((addr >> 7) & 0xe) | 0xa0;
    ipstart ();
    ipwrbyte (x);                                          // chip address 
    ipwrbyte (addr);                                       // word address 
    ipwrbyte (dat);                                        // data 
    ipstop ();
    dmsec (5);
}

unsigned char iprdep (unsigned int addr) {       // read 24lcxx (8 block) 
    unsigned char x,dat;                        
    x = ((addr >> 7) & 0xe) | 0xa0;
    ipstart ();                                  // set control 
    ipwrbyte (x);                                // chip address write 
    ipwrbyte (addr);                             // word address 
    ipstop ();
    dmsec (1);

    x = x | 1;
    ipstart ();                                  // read 
    ipwrbyte (x);                                // chip address read 
    dat = iprdbyte (); 
    ipstop ();
    return (dat);
}

void rtset (void) {                    // set RTC status bit 
    TIMBUF[0] = TIMBUF[0] & 0x7f;      // clear CH (clock halt) 
    TIMBUF[2] = TIMBUF[2] & 0xbf;      // set 24 hour 
    TIMBUF[7] = TIMBUF[7] & 0xec;      // b7=out b4=sqwe b1,b0=rs 
}

void rtwr (void) {                     // ds1307 rtc write 
    unsigned char i;                   
    ipstart ();
    ipwrbyte (0xd0);                   // address & r/w bit 
    ipwrbyte (0x00);                   // start register addr=0 
    for (i=0;i<=7;i++) {
        ipwrbyte (TIMBUF[i]);
    }
    ipstop ();
}

void rtrd (void) {                     // ds1307 rtc read 
    unsigned char i,dat;               
    ipstart ();
    ipwrbyte (0xd0);                   // address & r/w bit 
    ipwrbyte (0x00);                   // start register addr=0 
    ipstop ();
    ipdel ();

    ipstart ();
    ipwrbyte (0xd1);                   // address & r/w bit 
    for (i=0;i<=6;i++) {
        dat = iprdbytez ();
        TIMBUF[i] = dat;
    }
    dat = iprdbyte ();                 // last byte 
    TIMBUF[7] = dat;                   
    ipstop ();
}

void ip23008wr (unsigned char addr,com,dat) {         // mcp23008 write
    addr = ((addr << 1) & 0x0e) | 0x40;             
    ipstart ();                                  
    ipwrbyte (addr);
    ipwrbyte (com);
    ipwrbyte (dat);
    ipstop ();
}

/*
unsigned char ip23008rd (unsigned char addr,com) {    // mcp23008 read
    unsigned char dat;                               
    ipstart ();
    addr = ((addr << 1) & 0x0e) | 0x40;
    ipwrbyte (addr);
    ipwrbyte (com);
    ipstop ();

    ipstart ();
    addr = ((addr << 1) & 0x0e) | 0x41;
    ipwrbyte (addr);
    dat = iprdbyte (); 
    ipstop ();
    return (dat);
}
*/

void mcpword1 (unsigned int x) {            // mcp4921 write word (12 bit)
    unsigned char i;
    x = x | 0x3000;                         // daca,unbuffered,1x,output control bit
    MCPSCK = 0;
    MCPCS1 = 0;
    for (i=0;i<=15;i++) {
        if (x & 0x8000) MCPSDI = 1; else MCPSDI = 0;
        x <<= 1;
        _nop_ ();
        _nop_ (); 
    	MCPSCK = 1;
        _nop_ ();
        _nop_ (); 
        _nop_ ();
        _nop_ (); 
        MCPSCK = 0;
        _nop_ ();
        _nop_ (); 
    }
    MCPCS1 = 1;
}

void mcpword2 (unsigned int x) {            // mcp4921 write word (12 bit)
    unsigned char i;
    x = x | 0x3000;                         // daca,unbuffered,1x,output control bit
    MCPSCK = 0;
    MCPCS2 = 0;
    for (i=0;i<=15;i++) {
        if (x & 0x8000) MCPSDI = 1; else MCPSDI = 0;
        x <<= 1;
        _nop_ ();
        _nop_ (); 
    	MCPSCK = 1;
        _nop_ ();
        _nop_ (); 
        _nop_ ();
        _nop_ (); 
        MCPSCK = 0;
        _nop_ ();
        _nop_ (); 
    }
    MCPCS2 = 1;
}

unsigned int ubyte (unsigned int x) {  // max3100 read,write word   
    unsigned int y;
    unsigned char i;
    y = 0;
    UDOUT = 1;
    UCLK = 0;
    UCS = 0;
    for (i=0;i<=15;i++) {
        if (x & 0x8000) UDIN = 1; else UDIN = 0;
        x <<= 1;
        UCLK = 1;
        _nop_ ();
        _nop_ (); 
        y <<= 1; 
        if (UDOUT) y |= 1; 
        UCLK = 0;
    }
    UCS = 1;
    return (y);
}

void uset (void) {                // max3100 set (baud-rate)
    ubyte (0xc009);               // 19200
}

void usbyte (unsigned char a) {   // max3100 send byte
    unsigned int x;
    while (1) {
        x = ubyte (0x4000);
        if ((x & 0x4000)==0x4000) break;
    }
    x = 0x8000 | a;
    ubyte (x);
}

void usblock (void) {             // max3100 send block
    unsigned char i;
    i = 0;
	while (1) {
        if (STRBUF[i]==0) return;
        if (STRBUF[i]==0xa) {
	        usbyte (STRBUF[i++]); 
            usbyte (0xd); 
        }
		else usbyte (STRBUF[i++]); 
    }
}

unsigned char urbyte (void) {     // max3100 read byte
    unsigned int x;
    unsigned char a;
    while (1) {
        x = ubyte (0x4000);
        if ((x & 0x8000)==0x8000) break;
    }
    a = ubyte (0x0000);
    return (a);    
}

/********** UART FUNCTION **********/

unsigned char autobaud (void) {   // auto RS232 baud-rate (speed x1)
    unsigned char x;              // for clock 11.0592 Mhz
    unsigned int speed;           // start by SPACE character or ':'
                                  // auto 1200,2400,4800,9600,19200
    while (1) {
        TMOD = 0x10;              // timer-1 mode-1 16 bit counter
        TH1  = 0x00;
        TL1  = 0x00;
        TR1  = 0;
        while (RXD);              // wait for first start bit
        TR1  = 1;                 // start count
        while (~RXD);
        TR1  = 0;                 // stop count
        speed = TH1;
        speed <<= 8;
        speed |= TL1;             // speed = raw data
        dmsec (100);

        x = ' ';                            // check SPACE
        if (speed>4580 && speed<4620) {
            SPEEDM = 1200;
            return (x); 
        }
        else if (speed>2280 && speed<2320) {
            SPEEDM = 2400;
            return (x); 
        }
        else if (speed>1130 && speed<1170) {
            SPEEDM = 4800;
            return (x); 
        }
        else if (speed>556&& speed<596) {
            SPEEDM = 9600;
            return (x); 
        }
        else if (speed>268 && speed<308) {
            SPEEDM = 19200;
            return (x); 
        }

        x = ':';                            // check ':'
        if (speed>1514 && speed<1554) {
            SPEEDM = 1200;
            return (x); 
        }
        else if (speed>748 && speed<788) {
            SPEEDM = 2400;
            return (x); 
        }
        else if (speed>364 && speed<404) {
            SPEEDM = 4800;
            return (x); 
        }
        else if (speed>172 && speed<212) {
            SPEEDM = 9600;
            return (x); 
        }
        else if (speed>76 & speed<116) {
            SPEEDM = 19200;
            return (x); 
        }
        dmsec (100);
    }
}

void setbaud (void) {             // set RS232 baud rate (speed x1)
    SCON = 0x52;                  // for clock 11.0592 Mhz
    TMOD = 0x20;
    switch (SPEEDM) {
        case  1200: TH1 = 0xe8; break;
        case  2400: TH1 = 0xf4; break;
        case  4800: TH1 = 0xfa; break;
        case  9600: TH1 = 0xfd; break;
        case 19200: TH1 = 0xfd; PCON |= 0x80; break;
    }
    TR1 = 1;
}

unsigned char getkeyx (void) {    // getkey with delay
    unsigned char x;
	x = getkey ();
	dmsec (10);
	return (x);
}

void sendon (void) {                        // rs485 send on
    dmsec (5);
    D485 = 1;    
}

void sendoff (void) {                       // rs485 send off
    while (!TXOK);
    _nop_ ();
    _nop_ ();
    _nop_ ();
    _nop_ ();
    D485 = 0;
}

/********** INTERRUPT FUNCTION **********/

void input (unsigned char a) {              // input to COMBUF
    unsigned char i;                   
    if (a==':') {                           // start 
        COMINX = 0;  
        SCOMF = 1;
        for (i=0;i<=MAXBUF;i++) COMBUF[i] = 0;
    }

    else {
        if (SCOMF) {
            if (a==0x0d || a==0xff) {       // end
                COMBUF[COMINX] = a;
                SCOMF = 0;  
                RXOK = 1;
            }    
            else if (a<0x20) return;        // nothing
            else if (COMINX<MAXBUF) {
                COMBUF[COMINX] = a;         // command
                COMINX++;
            }
        }
    }
}

void serial (void) interrupt 4 {            // serial interrupt 
    unsigned char a;                        // receive binary command
    if (TI) {                               // TXD
        TI = 0;
        TXOK = 1;
        return;
    }

    a = SBUF;                               // RXD
    RI = 0;
    input (a);
}

                                            // modify function for printf		
char putchar (char x) {                     // send one byte  
    if (ACOMF) {
	    while (!TXOK);
    	TXOK = 0;
	    SBUF = x;
    }
	else {
        if (x=='\n') {
		    while (!TI);
		    TI = 0;
		    SBUF = 0x0d;                    
		}
	    while (!TI);
    	TI = 0;
	    SBUF = x;
	}
    return (x);
}

/********** TEST **********/

void test3b (void) {
    unsigned char a;
    printf ("\n\nTesting 3B Port (P12,P13,P14,P15,P16,P17) ...");
    printf ("\nType any keys to exit");
    a = 0;
    while (!RI) {
        BITMAP = a;
        P12 = B0;
        P13 = B1;
        P14 = B2;
        P15 = B3;
        P16 = B4;
        P17 = B5;
        dmsec (100);
        a++;
    }
    getkeyx ();
    P12 = 1;
    P13 = 1;
    P14 = 1;
    P15 = 1;
    P16 = 1;
    P17 = 1;
}

void testio (void) {
    unsigned char a;
    printf ("\n\nTesting I/O Port (P37,P11,P10) ...");
    printf ("\nType any keys to exit");
    a = 0;
    while (!RI) {
        BITMAP = a;
        P37 = B0;
        P11 = B1;
        P10 = B2;
        dmsec (300);
        a++;
    }
    getkeyx ();
    P37 = 1;
    P11 = 1;
    P10 = 1;
}

void test8b (void) {
    unsigned char i,k,j;
    printf ("\n\nTesting 8B Port (MCP23008) ...");
    ip23008wr (0,0xa,0x00);       // default port = 0xff
    ip23008wr (0,0,0);            // set all bit = out
    for (k=1;k<=3;k++) {
        j = 1;
        for (i=1;i<=8;i++) {
            ip23008wr (0,0xa,j);
            dmsec (300);
            j = j << 1;
        }
    }
    for (i=1;i<=3;i++) {
        j = 0x5555;
		ip23008wr (0,0xa,j);
        dmsec (1000);
        j = 0xaaaa;
		ip23008wr (0,0xa,j);
        dmsec (1000);
    }
    j = 0;
    ip23008wr (0,0xa,j);
}

void testda (void) {
    unsigned int x,y;
    printf ("\n\nTesting D/A (MCP4921) ch 1,2 ...");
    printf ("\nType any keys to exit");
    x = 0;
	y = 4095;
    while (!RI) {
	    mcpword1 (x);
		mcpword2 (y);
        dmsec (2);
        x++;
		if (x>4095) x = 0;
		y--;
		if (y==0xffff) y = 4095;
    }
	mcpword1 (0);
	mcpword2 (0);
    getkeyx ();
}

void testcom2 (void) {
    unsigned char x;
    bit f;
    printf ("\n\nTesting COM2 (MAX3100-RS232) ...");
    printf ("\nConnect to COM2 (19200,N,8,1)");
    printf ("\nand use command");
    printf ("\n:0<cr> = Check");
    printf ("\n:1<cr> = Exit (Delay 5 Sec)\n\n");
	uset ();
    while (1) {
        f = 0;  
        while (f==0) {                      // read command  
			if (urbyte ()==':') {
				x = urbyte ();
				if (urbyte ()==0xd) f = 1;
			}
		}
		if (x=='0') {                                 // check
			sprintf (STRBUF,"Test COM2 (485)\n");
			usblock ();
			dmsec (50);
		}
		else if (x=='1') {
			sprintf (STRBUF,"Bye !");
			usblock ();
			dmsec (5000);
			return;
		}
	}
}

void testkey (void) {
    unsigned char a,b,x,i;
    printf ("\n\nTesting Key1,Key2,Speaker ...");
    printf ("\nType any keys to exit");
    b = 0xff;
    while (!RI) {
        a = 0;
        if (KEY2==1) a |= 0x02;
        if (KEY1==1) a |= 0x01;
        if (a!=b) {
         	sound (30,10000);                
         	sound (20,10000);                
            printf ("\nKey1,Key2 = ");
            x = a;
            for (i=0;i<=1;i++) {
                if ((x & 0x1)==0) printf ("0"); else printf ("1");
                x >>= 1;
            }
            b = a;
        }
    }
    getkeyx ();
}

void test24lc04 (void) {
    bit err;
    printf ("\n\nTesting EEprom 24LC04 ... ");
    ipwrep (0,0xaa);
    ipwrep (1,0x55);
    err = 0;
    if (iprdep (0)!=0xaa) err = 1;
    if (iprdep (1)!=0x55) err = 1;
    if (err) printf ("Error !");
    else printf ("OK");
    printf ("\nType any keys ");
    getkeyx ();
}

void testrtc (void) {
    unsigned char x;
    printf ("\n\nTesting RTC DS1307 ...");
    printf ("\nType (S) to set time at 23:59:55 28/02/04");
    printf ("\nor any keys to Continue Display :");
    x = getkeyx ();
    if (x=='S' || x=='s') {
        TIMBUF[4] = 0x28;
        TIMBUF[5] = 0x02;
        TIMBUF[6] = 0x04;
        TIMBUF[3] = 0x01;
        TIMBUF[2] = 0x23;
        TIMBUF[1] = 0x59;
        TIMBUF[0] = 0x55;
        rtset ();
        rtwr ();
		dmsec (200);
    }
    printf ("\nType any keys to exit");
    x = 0xff;
    while (!RI) {
        dmsec (100);
        rtrd ();
        if (TIMBUF[0]!=x) {
            printf ("\ntime %02bx:%02bx:%02bx  date %02bx/%02bx/%02bx",
            TIMBUF[2],TIMBUF[1],TIMBUF[0],TIMBUF[4],TIMBUF[5],TIMBUF[6]);
            x = TIMBUF[0];
        }
    }
    getkeyx ();
}

/********** MAIN **********/

void com0 (void) {		          
    printf ("V-E54 v1.0 (Test RS485) \x0d\x0a");    // ???
}

void com485 (void) {
    unsigned char i;
    ACOMF = 1;                    // ascii command flag 
    ES = 1;                       // enable serial interrupt
    EA = 1;
    COMINX = 0;                   // start first command 
    SCOMF = 1;
    for (i=0;i<=MAXBUF;i++) COMBUF[i] = 0;
    while (1) {
        if (RXOK) {
            RXOK = 0;  
			sendon ();
            switch (toupper (COMBUF[0])) {
                case '0': com0 (); break;
            }
			sendoff ();
        }
    }
}

void start (void) {                    // start process 
    unsigned char i,a;
    unsigned int c;
	sound (30,20000);                  // power-up sound
    D485 = 0;
    TI = 1;                            // auto baud-rate
    a = autobaud ();
    setbaud ();
    if (a==':') com485 ();

    ACOMF = 0;
    sendon ();
    c = chks ();
    for (i=1;i<=22;i++) printf ("\n");
    printf ("V-E54 QC Program v1.0 (82E54AE)\n"); // ???
    printf ("Checksum=%04X Speed=%u\n",c,SPEEDM);
    printf ("2008 Sila Research Co.,Ltd.");
}

void main (void) {
    unsigned char a,i;
    bit f;
    a = 0;
    start ();
    f = 1;
    while (1) {
        if (f) {
            printf ("\n\n");                              
            printf ("   #### Main Menu #### \n");
            printf ("1. 3B Port (P12,P13,P14,P15,P16,P17) \n");
            printf ("2. I/O Port (P37,P11,P10) \n"); 
            printf ("3. 8B Port (MCP23008) \n");
	        printf ("4. D/A (MCP4921) \n");
            printf ("5. COM2 (MAX3100) \n");
            printf ("6. Key,Speaker \n");
            printf ("7. EEprom 24LC04 \n");
			printf ("8. RTC DS1307 \n");
            printf ("   Select :");
        }
        f = 0;
        if (a!=0) {i = a; a = 0;} else i = toupper (getkeyx ());
        switch (i) {
			case '1': f = 1; test3b (); break;
			case '2': f = 1; testio (); break;
			case '3': f = 1; test8b (); break;
			case '4': f = 1; testda (); break;
			case '5': f = 1; testcom2 (); break;
            case '6': f = 1; testkey (); break; 
			case '7': f = 1; test24lc04 (); break;
			case '8': f = 1; testrtc (); break;
			default: printf ("\a");
		}
    }
}

