/*
   mini1.c  limited version of code size for 89C52
   MiniLOGGER V1.0
   ADC: Dual-slope integrating type, CA3162 -10mV to +1000mV 1mV resolution
   MUX: CD4051 8-channel
   RTC: DS1202 Serial timekeeping
   Memory: Battery Backup 256kB (628128x2) approx. 5000 records
   Interfacing: MAX232
*/

#include "c:\mc\8051io.h"
#include "c:\mc\8051reg.h"
#include "c:\mc\8051bit.h"   // require preprocessor -P when compiling

#define word unsigned int
#define byte unsigned char
#define beginsysdata 0
#define beginrecord 100
#define begincrc 1000
#define status 0
/* system status eg., main/battery power, door open/close , digital input, analog input */
#define name 2

/*------------------------ DS1202 setting parameters -----------*/
#define rdsec  0x81
#define rdmin  0x83
#define rdhour 0x85
#define rddate 0x87
#define rdmonth 0x89
#define rdyear 0x8d
#define secu 0x8e
#define wrdate 0x86
#define wrmonth 0x88
#define wryear 0x8c
#define wrhour 0x84
#define wrmin 0x82
#define wrsec 0x80
#define unlock 0
#define lock 0x80
/*--------------------------------------------------------------*/

extern register char cputick;
unsigned register char sec100,sec,sec5,min,hour,day,month,year,flag1,ACCU,temp,led;
unsigned register char command,counter3;
unsigned register char BUFFER[50],mode;
char *title[] = "\n\nMiniLOGGER V1.0 COPYRIGHT (C) 1999,2000 WICHIT SIRICHOTE";
char *prompt[] = "\n>>";
/* char *menu[] = "\n\nHELP MENU\
                \n/ read once\
                \nt TIME set\
                \nd DATE set\
                \nc Clock display\
                \ns START/STOP recording time\
                \ni Interval\
                \n= setting parameters\
                \nr number of record\
                \ng Get record\
                \nn New record\
                \na ALL read\
                \n? help";
*/
unsigned register int blink_every;
unsigned register int count,number_of_record,counter1,counter2,interval,temp16,j;

unsigned register char pointer[3]; // 24 bit long number for external RAM pointer
unsigned register char temp1[3], temp2[3];
extern register char Longreg[];

/*-------------------- constant definition -------------------------*/
#define XOFF 0x13 // transmission flow control
#define XON 0x11
#define adj 2
#define LED P3.4
#define trigger P3.5
#define standby_blink 100
#define recording_blink 300
#define base 100  // start address for NVRAM storage
#define max_record 5000 //limit maximum record for 256kB SRAM (5000*50)

/*-------- address for setting parameters saved in NVSRAM 256 bytes page 0--*/
#define start_hour 0
#define start_min 1
#define stop_hour 2
#define stop_min 3
#define interval_saved 4 // 4-5 (16-bit)
#define record_saved 6 // 6-7 (16-bit) 
#define description 8 // 8-58 (max description string 50 characters)
#define mode_saved 60  // mode 1 manual, -1 auto

main()
{
  flag1 = 0;
  interval = 6000; // 60000 ms = 1 min
  blink_every = standby_blink;
  longset(pointer,100);  /* initialize pointer to 100 */

  reload_setting();   // reload previous recording setting
  disable();
  serinit(9600);
  putstr(*title);
  sendprompt();

  while(1)
  {
    tick_wait();  // 10 ms tasks tick 
/*------------- the following tasks execute every 10ms ------*/

    cpubeat();
    getcommand();
    printtime();
    settime();
    setdate();
    set_interval();
    dec_counter2();
    start_record();
    save_record();
    print_number_of_record();
    set_start_stop();
    new_record();
    show_setting();
//    print_menu();
    clock();
    read_all();
    manual_start_stop();
    prompting();
    }
/************************************************************/
}

int getnum()

{
    char s[6];      /* five characters plus terminator */
    char c;
    int i;
    for (i = 0; (c = putch(getch())) != 13; i++)
        s[i] = c;
        s[i] = '\0';
        if (i==0)
        return (-1);
        else
        return (_atoi(s));

}

char getbyte()
    
{
    char s[3];      /* two characters plus terminator */
    int i;
    for (i = 0; i < 2; i++)   /* read two characters then return value */
      s[i] = putch(getch());  // echo to terminal
      s[i] = '\0';
      return(((s[0]-0x30)<<4)|(s[1]-0x30)); // return BCD
   //  return (_atoi(s));                   // return binary
}

set_interval()
{
    if(command == 'i'){
     putstr("\n interval 10-600 sec > ");
     set_page(0);
     pokew(interval_saved,(getnum()*100)); // convert to *10 ms 
     interval = peekw(interval_saved);
     counter2 = interval; // load interval to counter2
     sendprompt();
                       }
}


dec_counter2()
{
   if ((flag1 & 0x08) != 0){
    counter2--;
    if(counter2 <= 0){
      counter2 = interval;
      flag1 |= 0x04;
                           }
                     }
}

start_record(){
    counter3--;
    if ( counter3 <= 0){
     counter3 = 100;  // run this task every 1 second
 if((rdds1202(rdhour) == peek(start_hour)) && (rdds1202(rdmin) == peek(start_min)))
        {flag1 |= 0x08; // start dec counter2
        blink_every = recording_blink;
        }
 if ((rdds1202(rdhour) == peek(stop_hour)) && (rdds1202(rdmin) == peek(stop_min)))
        {flag1 &= ~0x08; //  disable running dec_counter2
        blink_every = standby_blink;
        }
                        }
}


settime()

{
    if (command == 't')
    {
    command = '/';
//    printtime();
    putstr(" HH:MM:SS = ");
    writertc(secu,unlock);
    writertc(wrhour,getbyte());
    putch(':');
    writertc(wrmin,getbyte());
    putch(':');
    writertc(wrsec,getbyte());
    writertc(secu,lock);

    sendprompt();
    }
}

setdate()

{
    if (command == 'd')
    {
    command = '/';
  //  printtime();
    putstr(" DD/MM/YR = ");
    writertc(secu,unlock);
    writertc(wrdate,getbyte());
    putch('/');
    writertc(wrmonth,getbyte());
    putch('/');
    writertc(wryear,getbyte());
    writertc(secu,lock);
    sendprompt();
    }
}

prompting()
 
{
    if (command == 13)
       {
        putstr(*title);
        sendprompt();
       }
}

printtime()
{
      if (command == '/')
      {
   printf("\n%02x/%02x/%02x ",rdds1202(rddate),rdds1202(rdmonth),rdds1202(rdyear));   
   printf("%02x:%02x:%02x ",rdds1202(rdhour),rdds1202(rdmin),rdds1202(rdsec));
      read_DVM();
      printf("%i",BUFFER); /* for testing */
        sendprompt();
      }
}

getcommand()
{

    if ((SCON & 0x01) != 0)
        command = putch(getch());
    else command = -1;             /* no cammand has entered */
}

sendprompt()
{
    putstr(*prompt);
}


pause(int j)
{
   int i;
   for (i = 0; i < j; i++)
   ;
}


cpubeat()
{
    beat5sec();
    livecpu();

}

beat5sec()  /* clear P3.4 every 500 tocks */

{
       counter1++;
        if (counter1 > blink_every )
        {
           counter1 = 0;
           flag1 |= 0x40; /* set bit 6 of flag1 to signal livecpu task */
           clrbit(LED)  //asm " CLR P3.4";
           led = 5;      /* 5*10ms = 50ms LED on */
        }

}

livecpu()

{
    if ((flag1 & 0x40) != 0)
      {
        led--;
        if (led == 0)
           {
           setbit(LED)  //asm " SETB P3.4";
           flag1 &= ~0x40;
           }
    }
}


read_DVM() /* read digital data from SOLAR3, save in BUFFER */
{
    int i;
    char c;
    clrbit(trigger) //asm" CLR P3.5";     // trigger read
    clrbit(LED) //asm" CLR P3.4";     // while reading turn LED on
    for (i = 0; (c = getchr()) != 0; i++)
        BUFFER[i] = c;
        BUFFER[i] = '\0';
        setbit(trigger) //asm" SETB P3.5";
        setbit(LED) //asm" SETB P3.4"; // then off
   //     printf("%i",BUFFER); /* for testing */
}


tick_wait()
{
    asm {
    JNB TCON.5,*      /* wait for timer0 overflow */
    CLR TCON.5
    ORL TH0,#$DC     /* reload $DC00, i.e., for 10ms overflow */
    }
}

/*---------------------- DS1202 RTC driver routine ------------------*/
writertc(char a, char b)
{
	int i;
	   i = a;
	   i <<= 8;
	   i |= b;
	   wrds1202(i);
}

set_page(unsigned char p)  /* set page address for A16 (P1.0), CHIP SELECT P1.1 and P1.2 */
/* pointer[0] and [1] 16 bit are used for low 16-bit addressing
   pointer[1] bit 0 is for A16
              bit 1 is for A17  if A17 = 0 then SETB P1.1 & CLR P1.2
                                if A17 = 1 then CLR  P1.1 & SETB P1.2
*/            

{
                temp = p; //pointer[2];
     asm {
                MOV   A,temp
                MOV   C,ACC.0              emits A16
                MOV   P1.0,C
                JB    ACC.1,A17_HIGH
                SETB  P1.1                A17 low then select chip #1
                CLR   P1.2
                SJMP  SET_ADDRESS_OK
A17_HIGH        SETB  P1.2                A17 high then select chip #2
                CLR   P1.1
SET_ADDRESS_OK  NOP
          }
}

int get_address()  /* return address pointer */ 
{
    int i;
    i = pointer[1];
    i <<= 8;
    return(i|pointer[0]);
}

inc_pointer()
{
   asm{
    MOV   A,#$1
    ADD   A,pointer
    MOV   pointer,A
    CLR   A
    ADDC  A,pointer+1
    MOV   pointer+1,A
    CLR   A
    ADDC  A,pointer+2
    MOV   pointer+2,A
      }
}
   

int set_RAM_address() /* increment next address for external 256kB SRAM */
{
    inc_pointer();
    set_page(pointer[2]);
    return(get_address());
}

char convert_hi_nibble(unsigned char c)
{
    return((c>>=4)+0x30);
}

char convert_lo_nibble(char c)
{
   return((c&0x0f)+0x30);
}

save_record()
{
     if((flag1 & 0x04) != 0)
     {
        read_DVM();
        // save date & time in ASCII
        poke(set_RAM_address(),convert_hi_nibble(rdds1202(rddate)));
        poke(set_RAM_address(),convert_lo_nibble(rdds1202(rddate)));
        poke(set_RAM_address(),convert_hi_nibble(rdds1202(rdmonth)));
        poke(set_RAM_address(),convert_lo_nibble(rdds1202(rdmonth)));
        poke(set_RAM_address(),convert_hi_nibble(rdds1202(rdyear)));
        poke(set_RAM_address(),convert_lo_nibble(rdds1202(rdyear)));

        poke(set_RAM_address(),convert_hi_nibble(rdds1202(rdhour)));
        poke(set_RAM_address(),convert_lo_nibble(rdds1202(rdhour)));
        poke(set_RAM_address(),convert_hi_nibble(rdds1202(rdmin)));
        poke(set_RAM_address(),convert_lo_nibble(rdds1202(rdmin)));
        poke(set_RAM_address(),convert_hi_nibble(rdds1202(rdsec)));
        poke(set_RAM_address(),convert_lo_nibble(rdds1202(rdsec)));

     // now save the BUFFER
    for (j = 0; BUFFER[j] != '\0'; j++)
        poke(set_RAM_address(),BUFFER[j]);
        poke(set_RAM_address(),'\0');  // put line terminator
        flag1 &= ~0x04;
        ++number_of_record;
        max_limit(); // check maximum for 5000 records
        set_page(0);
        pokew(record_saved,number_of_record); // save available records
        printf("%u",number_of_record);
    //    putch('.');  // sending flag to host after record has been saved
      }
}

max_limit(){   // disable recording mode if number of record > max_record
        if(number_of_record > max_record)
          {flag1 &= ~0x08; //  disable running dec_counter2
           blink_every = standby_blink;
           poke(mode_saved,-1); // change to auto mode indicating maximum limited
          }
}

print_number_of_record()
{
     if (command == 'r')
     {
       printf("\n%u records available",number_of_record);
       sendprompt();
      }
}
/*
get_record()      // test reading until found record terminator
{
    char i;
    if (command == 'g')
    {
    putch('\n');
    j = 101;
    for (j = 101; j< 101+(number_of_record*46); j = j+46)
    {
    for ( i = 0; i <46; i++)
     {
     if(peek(i+j) != 0)
         putch(peek(i+j));
         else putch('\n');
     }
     }
     sendprompt();
    }
}

*/

set_start_stop()
{
        if (command == 's'){
        set_page(0);
        printf("\nSTART %02x:%02x >",peek(start_hour),peek(start_min));
        poke(start_hour,getbyte()); // save new start time
        putch(':');
        poke(start_min,getbyte());
        printf("\nSTOP  %02x:%02x >",peek(stop_hour),peek(stop_min));
        poke(stop_hour,getbyte());
        putch(':');
        poke(stop_min,getbyte());
        printf("\n %02x:%02x %02x:%02x",peek(start_hour),peek(start_min),peek(stop_hour),peek(stop_min));
        swapping_mode();
        sendprompt();
                             }
}

swapping_mode()   // enable/disable manual check
{
        if (peek(start_hour) == 0x99)
            poke(mode_saved,1); // manual mode
            else (poke(mode_saved,-1)); // automatic mode
}

show_setting(){

      if (command == '='){
      set_page(0);
      printf("\n START %02x:%02x",peek(start_hour),peek(start_min));
      printf("\n STOP  %02x:%02x",peek(stop_hour),peek(stop_min));
      printf("\n SAMPLING INTERVAL(sec) = %u",peekw(interval_saved)/100);
      if (peek(mode_saved) == 1)
      printf("\n MANUAL");
      else (printf("\n AUTO"));
      sendprompt();
      }
}

reload_setting(){
     set_page(0);
     interval = peekw(interval_saved);
     counter2 = interval;
     number_of_record= peekw(record_saved);
     longset(temp2,46);     // temp2 = 46
     longset(temp1,number_of_record);  // temp1 = number of record
     longmul(temp1,temp2);  // Longreg = temp1*temp2
     longset(temp1,base);   // temp1 = base = 100
     longadd(Longreg,temp1);  // Longreg = Longreg + temp1
     longcpy(pointer,Longreg); // restore pointer
}


new_record()
{
     if (command == 'n')
     {
     putstr("\n New record?(Y/N)");
     if (getch() == 'y')
        { flag1 &= ~0x08;  // reset start bit enable
          number_of_record = 0;
          pokew(record_saved,0); // reset number of record to 0
          longset(pointer,base);
          enter_description();
         }
         sendprompt();
     }
}

/*
print_menu(){
        if (command == '?'){
        putstr(*menu);
        sendprompt();
        }
}
*/


clock(){
        if (command == 'c'){
   printf("\n %02x/%02x/%02x ",rdds1202(rddate),rdds1202(rdmonth),rdds1202(rdyear));   
   printf("%02x:%02x:%02x ",rdds1202(rdhour),rdds1202(rdmin),rdds1202(rdsec));
        sendprompt();
        }
}

read_all()  // read all record from 100 to current pointer
{
        if (command == 'a'){

        send_description();
        longset(temp1,1);        // decrement pointer
        longsub(pointer,temp1);  
        longcpy(temp1,pointer);  // copy end address to temp1
        longset(pointer,100);  // point to start of NVRAM

        while (longcmp(temp1,pointer) > 0)
           {
            for (j = 0; j < 46; j++)
                BUFFER[j] = peek(set_RAM_address());
                BUFFER[j] = 0;
 //               printf("\n %i",BUFFER);
               send_formatted_record();
               see_XOFF();
             }      
         sendprompt();
                           }
}

send_formatted_record()
{
  send(0x0d);
  send(0x0a);
  printf("%c%c/%c%c/%c%c",BUFFER[0],BUFFER[1],BUFFER[2],BUFFER[3],BUFFER[4],BUFFER[5]);    
  printf(",%c%c:%c%c:%c%c",BUFFER[6],BUFFER[7],BUFFER[8],BUFFER[9],BUFFER[10],BUFFER[11]);
  for(j = 0; j< 24; j+=3)  // skip BUFFER[12] = *
  printf(",%c%c%c",BUFFER[13+j],BUFFER[14+j],BUFFER[15+j]);
  printf(",%c%c%c%c%c%c",BUFFER[37],BUFFER[38],BUFFER[39],BUFFER[40],BUFFER[41],BUFFER[42]);
}

see_XOFF()
{
      char c;
        if ( chkchr() == XOFF)
           { 
             while( c != XON)
             c = chkchr();
            }
}

send(char a)    // Dave's putch() automatically send 0x0d after 0x0a
{
        temp = a;
        asm{
        JNB  SCON.1,*
        CLR  SCON.1      
        MOV  A,temp
        MOV  SBUF,A      
            }
}

enter_description()
{
        putstr("\n<-- Enter description text (max 50 characters)-->\n");
        _getstr(BUFFER,50);  // get string max 50 characters
        set_page(0);
        for (j = 0; BUFFER[j] != '\0'; j++)  // save to NVRAM
           poke((description+j),BUFFER[j]);
        poke((description+j),'\0');  // put line terminator
       // sendprompt();
}

send_description()
{
        char c;
        send(0x0d);
        send(0x0a);
        set_page(0);
        for (j = 0; (c = peek(description+j)) != '\0'; j++)
          putch(c);
}

manual_start_stop(){
        set_page(0);
     if (peek(mode_saved) == 1){
        if((P3 & 0x04) == 0)
        {flag1 |= 0x08; // start dec counter2
        blink_every = recording_blink;
        }
        else
        {flag1 &= ~0x08; //  disable running dec_counter2
        blink_every = standby_blink;
        }
                                }
}
