;************************************************************************
;
;              Miniature Realtime Controller V2.0
;                     ws  25 July 1994
;                 1st modified 3 December 1995
;                 for a miniature 89C2051 SCM
;                       2KB code memory
; specifications:
; 89c2051 @3.579545MHz + MAX232C + 74LS07
; programmed via serial port using on-chip data memory for saving timing
; control code.
;************************************************************************

;
;

         CPU       "8051.TBL"
         HOF       "INT8"
;
;
;MCS-51 INTERNAL REGISTERS
;
B:        EQU       0F0H      ;B REGISTER
ACC:      EQU       0E0H      ;ACCUMULATOR
PSW:      EQU       0D0H      ;PROGRAM STATUS WORD
IPC:      EQU       0B8H      ;INTERRUPT PRIORITY
P3:       EQU       0B0H      ;PORT 3
IEC:      EQU       0A8H      ;INTERRUPT ENABLE
P2:       EQU       0A0H      ;PORT 2
SBUF:     EQU       99H       ;SEND BUFFER
SCON:     EQU       98H       ;SERIAL CONTROL
P1:       EQU       90H       ;PORT 1
TH1:      EQU       8DH       ;TIMER 1 HIGH
TH0:      EQU       8CH       ;TIMER 0 HIGH
TL1:      EQU       8BH       ;TIMER 1 LOW
TL0:      EQU       8AH       ;TIMER 0 LOW
TMOD:     EQU       89H       ;TIMER MODE
TCON:     EQU       88H       ;TIMER CONTROL
PCON:     EQU       87H       ;POWER CONTROL REGISTER
DPH:      EQU       83H       ;DATA POINTER HIGH
DPL:      EQU       82H       ;DATA POINTER LOW
SP:       EQU       81H       ;STACK POINTER
P0:       EQU       80H       ;PORT 0
;
;MCS-51 INTERNAL BIT ADDRESSES
;
CY:       EQU       0D7H      ;CARRY FLAG
AC:       EQU       0D6H      ;AUXILIARY-CARRY FLAG
F0:       EQU       0D5H      ;USER FLAG 0
RS1:      EQU       0D4H      ;REGISTER SELECT MSB
RS0:      EQU       0D3H      ;REGISTER SELECT LSB
OV:       EQU       0D2H      ;OVERFLOW FLAG
P:        EQU       0D0H      ;PARITY FLAG
PS:       EQU       0BCH      ;PRIORITY SERIAL PORT
PT1:      EQU       0BBH      ;PRIORITY TIMER 1
PX1:      EQU       0BAH      ;PRIORITY EXTERNAL 1
PT0:      EQU       0B9H      ;PRIORITY TIMER 0
PX0:      EQU       0B8H      ;PRIORITY EXTERNAL 0
EA:       EQU       0AFH      ;ENABLE ALL INTERRUPT
ES:       EQU       0ACH      ;ENABLE SERIAL INTERRUPT
ET1:      EQU       0ABH      ;ENABLE TIMER 1 INTERRUPT
EX1:      EQU       0AAH      ;ENABLE EXTERNAL 1 INTERR
ET0:      EQU       0A9H      ;ENABLE TIMER 0 INTERRUPT
EX0:      EQU       0A8H      ;ENABLE EXTERNAL 0 INTERR
SM0:      EQU       09FH      ;SERIAL MODE 0
SM1:      EQU       09EH      ;SERIAL MODE 1
SM2:      EQU       09DH      ;SERIAL MODE 2
REN:      EQU       09CH      ;SERIAL RECEPTION ENABLE
TB8:      EQU       09BH      ;TRANSMITT BIT 8
RB8:      EQU       09AH      ;RECEIVE BIT 8
TI:       EQU       099H      ;TRANSMIT INTERRUPT FLAG
RI:       EQU       098H      ;RECEIVE INTERRUPT FLAG
TF1:      EQU       08FH      ;TIMER 1 OVERFLOW FLAG
TR1:      EQU       08EH      ;TIMER 1 RUN CONTROL BIT
TF0:      EQU       08DH      ;TIMER 0 OVERFLOW FLAG
TR0:      EQU       08CH      ;TIMER 0 RUN CONTROL BIT
IE1:      EQU       08BH      ;EXT INTERR. 1 EDGE FLAG
IT1:      EQU       08AH      ;EXT INTERR. 1 TYPE FLAG
IE0:      EQU       089H      ;EXT INTERR. 0 EDGE FLAG
IT0:      EQU       088H      ;EXT INTERR. 0 TYPE FLAG
										; PORT 1 BIT ADDRESS
P1.0:     EQU       090H      ;  START COMMAND
P1.1:     EQU       091H      ;  select A-B only or A-B-C-D
P1.2:     EQU       092H      ;
P1.3:     EQU       093H      ;
P1.4:     EQU       094H      ; output soleniod #4  option
P1.5:     EQU       095H      ; output solenoid #3  option
P1.6:     EQU       096H      ; output solenoid #2 ---> A-C
P1.7:     EQU       097H      ; output solenoid #1 ---> A-B

p2.0:     equ       0a0h      ; time base indicator
p2.1:     equ       0a1h      ; clock out 50.000 Hz for calibration !
p2.2:     equ       0a2h      ; tone output

p3.0:     equ       0b0h
p3.1:     equ       0b1h
p3.2:     equ       0b2h
p3.3:     equ       0b3h
p3.4:     equ       0b4h
p3.5:     equ       0b5h
p3.6:     equ       0b6h
p3.7:     equ       0b7h
  

SAVE_L:   EQU       048H      ; SAVE POINTER USE IN INTERRUPT SERVICE
SAVE_H:   EQU       049H      ; ROUTINE
STATE:    EQU       038H      ; STATE BYTE 1 = TIME
										;            2 = PROGRAM

			; RAM BIT ADDRESS

serial:   equ        18h      ; on/off send data
sim:      equ        19h      ; simulate mode (speed-up test)
blink:    equ        1Ah
output:   equ        21h      ; 16 bit output cuntrol 21h 22h

KEY:      EQU        0BH
LED:      EQU        08H      ; INTERRUPT BLINK
XOFF_FLAG:EQU        0AH
ZEROING:  EQU        0DH
VALVE:    EQU        0EH
CYCLE_COUNT: EQU     0FH


;current time storage

sec100:   equ        25h
sec:      equ        26h
min:      equ        27h
hour:     equ        28h
day:      equ        29h
MONTH:    EQU        2AH
YEAR:     EQU        2BH
warm_code: equ       2Eh
light:     equ       2dh
econo:     equ       2ch
tl0adj:    equ       2fh
pgm_buffer: equ      30h     ; start from 30h



RECEIVE_BUFFER: EQU  4AH

TOP_FIFO: EQU       1000H     ; TOP OF FIFO BUFFER

CR:       EQU        0DH
LF:       EQU        0AH
EOS:      EQU        10H
BELL:     EQU        07H


;******************************************************
;

      ORG       000H
			LJMP      MAIN_TIMER

      org       003h
      ljmp      service_int0  ; for airconditioner start manually

      ORG       00BH
			LJMP      SERVICE_T0 ; TIMER COUNTER 0 INTERRUPT


			ORG       0100H

;INIT_RS232C INITIALIZED 89C2051 SERIAL PORT
;            BAUD RATE: 9600
;            DATA LENGTH: 8 BIT
;            STOP BIT: 1 BIT
;            PARITY: NO
;            X-TAL: 3.579545 MHz

INIT:    MOV       TMOD,#00100001B
         MOV       SCON,#01010010B
         MOV       PCON,#10000000B ; smod = 1
         MOV       TH1,#0FEH       ;TIMER1 LOAD VALUE
         SETB      TR1             ;START TIMER1
         RET


;SEND    SEND A TO SERIAL PORT
;        CHECK TRANSMITTER BUFFER BEFORE SEND
;
;        ENTRY: A
;        EXIT: NO
;
SEND:    JNB       TI,SEND
         CLR       TI
         MOV       SBUF,A          ;OK BUFFER EMPTY SEND OUT...
         RET

;
;RECIVES RECIVE BYTE FROM SERIAL PORT WITH TIME-OUT FUNCTION
;        ENTRY: NO
;        EXIT: A = ASCII NUMBER OR STRING COMMAND
;					A = FF  TIME-OUT

RECIVES:   MOV     R7,#05H
AGAIN:	  MOV     R6,#00H          ; TIME-OUT DELAY
GET_RI:	  JB      RI,READY

			  DJNZ    R6,GET_RI
			  DJNZ    R7,AGAIN
			  MOV     A,#0FFH           ; TIME-OUT NO DATA RECEPTED
			  RET
READY:	  CLR     RI
			  MOV     A,SBUF
			  RET


;RECIVE  RECIVE BYTE PUT TO A FROM SERIAL PORT
;        WAIT UNTIL RECIVER BUFFER READY
;        ENTRY: NO
;        EXIT: A

RECIVE:  JNB       RI,RECIVE
         CLR       RI
         MOV       A,SBUF      ; GET IT
         LCALL     SEND        ; ECHO TO TERMINAL
         RET

;SEND_PROMPT

SEND_PROMPT: LCALL   CR_LF
             MOV     DPTR,#PROMPT
             LCALL   SEND_STRING
             RET


;CR_SEND SEND CR TO RS232
;        ENTRY: NO
;        EXIT: NO
;
CR_LF:   MOV       A,#CR
         LCALL     SEND
			MOV       A,#LF
			LCALL     SEND
			RET

XOFF:    EQU        13H
XON:     EQU        11H
BREAK:   EQU        00H
EOF:     equ        0FH


;SEND_XOFF SEND XOFF TO RS232
;        ENTRY: NO
;        EXIT: NO
;
SEND_XOFF: MOV     A,#XOFF    ;GET XOFF CHARACTER
           LCALL     SEND
           RET

;SEND_XON
;
;
;
SEND_XON: MOV      A,#XON
          LCALL    SEND
          RET
;SPACE

SPACE:    MOV     A,#20H
          LCALL   SEND
          RET

;ASCII_BIN  CONVERTS SINGLE ASCII CHARACTER TO SINGLE NIBBLE
;           BINARY
;         ENTRY: A ( 30-39 for 0-9, 41-46 for A-F, 61-66 for a-f)
;         EXIT: A
;         ignor lower case clr bit 5 before

ASCII_BIN: CLR      C
			  MOV      R6,A
			  SUBB     A,#41H
			  JNC      ASCII_AF
			  MOV      A,R6
			  CLR      C
			  SUBB     A,#30H
			  RET
ASCII_AF:  CLR      C
			  MOV      A,R6
			  SUBB     A,#37H
			  RET

;COMBINE DATA 2 BYTE TO SINGLE BYTE
;        ENTRY: R4= LOW NIBBLE
;               R5= HIGH NIBBLE
;        EXIT:  A
;
COMBINE: MOV        A,R5
         SWAP       A
         ADD        A,R4
				 RET

;GET_BYTE GET DATA FROM SERIAL PORT TWO BYTE SAVE TO
;        R5 AS A HIGH NIBBLE AND R4 AS A LOW NIBBLE
;        ENTRY: NO, serial port must be initialzed before calling
;        EXIT: A
;
;
GET_BYTE:  LCALL      RECIVE ; FIRST READING MUST GO TO R5 !!
				 LCALL      ASCII_BIN
				 MOV        R5,A
         LCALL      RECIVE
				 LCALL      ASCII_BIN
				 MOV        R4,A
         LCALL      COMBINE
         RET


;BIN_ASCII CONVERT BIN TO ASCII CODE
;         ENTRY: A
;         EXIT : A
BIN_ASCII:
				  ANL     A,#0FH
				  MOV     R2,A
				  CLR     C
				  SUBB    A,#0AH
				  JNC     ASCII_AF2
				  MOV     A,R2
				  ADD     A,#30H
				  RET
ASCII_AF2:     MOV     A,R2
				  ADD     A,#37H
				  RET

;BYTE_ASCII  CONVERT A TO ASCII IN R4, R5

BYTE_ASCII:   MOV    B,A
				  LCALL  BIN_ASCII

				  MOV    R4,A
				  MOV    A,B
				  SWAP   A
				  LCALL  BIN_ASCII
				  MOV    R5,A
				  RET

;SEND_ASCII SEND ASCII IN R5(HI) R4(LO) BYTE TO MONITOR
;          INPUT : A
;          OUTPUT : NONE
SEND_ASCII:  LCALL  BYTE_ASCII
				 MOV    A,R5
				 LCALL  SEND
				 MOV    A,R4
				 LCALL   SEND
				 RET


;NIBBLE_SHIFT SHIFT FOUR DIGIT BCD NUMBER LEFT A NIBBLE
;           ENTRY : R0 POINTED TO LSD
;           EXIT : NO

NIBBLE_SHIFT:  INC  R0
					MOV  A,@R0
					SWAP A
					ANL  A,#0F0H
					MOV  R1,A
					DEC  R0
					MOV  A,@R0
					SWAP A
					MOV  R2,A
					ANL  A,#0FH
					ADD  A,R1
					INC  R0
					MOV  @R0,A
					MOV  A,R2
					ANL  A,#0F0H
					DEC  R0
					MOV  @R0,A
					RET


;SHIFT_16BIT SHIFT LEFT 1 BIT ADDRESS $3D,$3E
;            $3D  LO BYTE
;            $3E  HI BYTE
;            ENTRY: NO
;            EXIT: Carry Flag

SHIFT_16BIT: CLR    C          ;     {($3E,$3D)} X 2
				 MOV    A,3DH
				 ADD    A,3DH
				 MOV    3DH,A
				 MOV    A,3EH
				 ADDC   A,3EH
				 MOV    3EH,A
				 RET               ; CARRY GONE

;BIN_BCD CONVERT 16 BIT BINARY TO BCD
;        SHIFT LEFT 1 BIT FROM MOST SIGNIFICANT BIT TO LEAST SIGNIFICANT
;        BIT , IF CARRY = 1 THEN BCD= (2^N + BCD)
;
; 		  ENTRY: 16 BIT DATA
;               $3D = LO BYTE
;               $3E = HI BYTE
;       EXIT: 6 DIGIT BCD
;               $36L =      0
;               $36H =     10
;               $37L =    100
;               $37H =   1000
;               $38L =  10000
;               $38H = 100000

BIN_BCD:   MOV     36H,#00     ; CLEAR BCD BEFORE
			  MOV     37H,#00
			  MOV     38H,#00

			  MOV     R1,#00H
			  MOV     R7,#16D
BIN_1:	  LCALL   SHIFT_16BIT
        JNC     NEXT_BIT

;     OK CARRY = 1 ADD BCD TO 2^N CONSTANT IN TABLE2
			  MOV     DPTR,#TABLE2
			  CLR     C
			  MOV     R0,#36H
			  MOV     R6,#03H
BIN_2:	  MOV     A,R1
			  MOVC    A,@A+DPTR
			  ADDC     A,@R0
			  DAA
			  MOV     @R0,A
			  INC     DPTR
			  INC     R0
			  DJNZ    R6,BIN_2

NEXT_BIT:  INC     R1
			  INC     R1
			  INC     R1
			  DJNZ    R7,BIN_1
			  RET

TABLE2:	  DFB     68H,27H,03H
			  DFB     84H,63H,01H
			  DFB     92H,81H,00H
			  DFB     96H,40H,00H
			  DFB     48H,20H,00H
			  DFB     24H,10H,00H
			  DFB     12H,05H,00H
			  DFB     56H,02H,00H
			  DFB     28H,01H,00H
			  DFB     64H,00H,00H
			  DFB     32H,00H,00H
			  DFB     16H,00H,00H
			  DFB     08H,00H,00H
			  DFB     04H,00H,00H
			  DFB     02H,00H,00H
			  DFB     01H,00H,00H

;########################################################################
;           TIMER 0 INTERRUPT SERVICE ROUTINE                           #
;          enter to this routine every 1/10 Hz                     #
;            update current time and date                               #
;            check current day and time every 1 sec                     #
;            if current time =  set time the activates 8 output bit     #
;                                                                       #
;########################################################################

SERVICE_T0:   PUSH   PSW
				  PUSH   ACC
				  PUSH   B
				  PUSH   DPL
				  PUSH   DPH
				  MOV    PSW,#00001000B  ; SELECT REGISTER BANK 1

; TIMER 0 SERVICE BODY

         ; cpl    p3.5               ; check time base should be 10/2 Hz

          MOV    TH0,#COUNT_H
          MOV    TL0,tl0adj         ; get low byte adjustable
          lcall   light_on
          inc    sec100             ;
          mov    a,sec100
          cjne   a,#0AH,CHECK_SEC   ; update second every 10 counts

          inc    econo
          mov    a,econo
          cjne   a,#05h,skip_econo
          mov    econo,#00h
          setb   blink
          clr    p3.7               ; turn on light every 5 second
                                    ; since inc sec100 as binary
skip_econo:

          lcall  io_out
          jnb    serial,no_send

          LCALL SEND_TIME

no_send:  mov    sec100,#00h
          mov    a,sec
          add    a,#01d
          daa
          mov    sec,a


CHECK_SEC:
          mov    a,sec
          cjne   a,#60H,CHECK_MIN
          jnb    sim,min_send
          lcall  send_time

min_send:
          mov    sec,#00d
          mov    a,min
          add    a,#01d
          daa
          mov    min,a
   
CHECK_MIN:
          mov    a,min
          cjne   a,#60H,CHECK_HOUR
          mov    min,#00d
          mov    a,hour
          add    a,#01d
          daa
          mov    hour,a

CHECK_HOUR:
          mov   a,hour
          cjne  a,#24h,check_day
          mov   hour,#00d
          mov   a,day
          add   a,#01d
          daa
          mov   day,a

check_day:
          lcall get_month_day
          mov   a,day
          cjne  a,b,check_month
          mov   day,#01d
          mov   a,month
          add   a,#01d
          daa
          mov   month,a

check_month:
          mov   a,month
          cjne  a,#13h,check_year
          mov   month,#01d
          mov   a,year
          add   a,#01d
          daa
          mov   year,a

check_year:


				  POP   DPH
				  POP   DPL
				  POP   B
				  POP   ACC
				  POP   PSW
				  RETI


;send_output send output (display) to terminal for simulate test

send_outputs:
         lcall space
         lcall space
         mov   r6,#01d                  ; tiny timer 8 bit I/O $21
         mov   dptr,#output_prompt
         lcall send_string
         mov   r0,#output
outer:   mov   r7,#08d
         mov   a,@r0
         cpl   a                        ; sink current drive circuit
         MOV   P1,A                     ; send current output to port 1
         cpl   a
         mov   b,a
inner:   mov   a,b
         rlc   a
         mov   b,a
         jc    on_contact
         mov   a,#"-"
         lcall send
         lcall space
         sjmp  next_bits

on_contact:
         mov   a,#"O"
         lcall send
         lcall space

next_bits: djnz r7,inner
          inc   r0
          djnz  r6,outer
          ret

;light_on blink led shows time base is run

light_on:   jnb   blink,led_on ; if blink not set do not count down
            mov   a,light
            inc   a
            mov   light,a
            cjne  a,#01h,led_on
            mov   light,#00h
            setb   p3.7          ; off light
            clr    blink         ; finished blink
led_on:     ret

;send_tone send tone like beep beep to p2.2

send_tone:  mov   r7,#00h
tone0:      clr   p2.2
            mov   r6,#50h
tone1:      djnz  r6,tone1
            setb  p2.2
            mov   r6,#50h

tone2:      djnz  r6,tone2
            djnz  r7,tone0
            ret


;BCD_ASCII CONVERT BCD NUMBER TO ASCII CODE
;          ENTRY: A {LOW NIBBLE ONLY}
;          EXIT: A

BCD_ASCII: ANL       A,#0FH           ;GET ONLY LOW NIBBLE
			  ADD       A,#30H           ;CONVERT TO ASCII CODE
			  RET

;send current time

send_time:

            LCALL CR_LF
            MOV   A,DAY
            LCALL SEND_ASCII
            MOV   A,#"-"
            LCALL SEND
            MOV   A,MONTH
            LCALL SEND_ASCII
            MOV   A,#"-"
            LCALL SEND
            MOV   A,#25H
            LCALL SEND_ASCII
            MOV   A,YEAR
            LCALL SEND_ASCII
            LCALL SPACE


            MOV   A,HOUR
            LCALL SEND_ASCII
            MOV   A,#":"
            LCALL SEND
            MOV   A,MIN
            LCALL SEND_ASCII
            MOV   A,#":"
            LCALL SEND
            MOV   A,SEC
            LCALL SEND_ASCII
            lcall send_outputs


            RET



;io_out send output o1-o8 when current time = setting time
;         scan setting time and compare current time
;               if current time = set time then activate i/o
;                els next set time till eof found

io_out:     mov   r0,#pgm_buffer
io0:        mov   a,@r0
            cjne  a,#eof,io1
            ret


io1:        jb    p3.5,skip_day    ; if p3.7 = 0 then skip day checking
            cjne  a,day,io4        ; check day

skip_day:   inc   r0
            mov   a,@r0
            cjne  a,hour,io2       ; check hour
            inc   r0
            mov   a,@r0
            cjne  a,min,io3        ; check min
            inc   r0               ; current time = set time
            mov   a,@r0            ; get output
            mov   output,a         ; put to output byte
            cpl   a                ; i.e., sink current is used for driving LED
            mov   p1,a             ; activate port 1 also
            ret

io4:        inc   r0
io2:        inc   r0
io3:        inc   r0
            inc   r0
            sjmp  io0


;GET_MONTH_DAY get day-end of each month, e.g. Jan=31, Feb=28, Mar=31,..
;              ,etc.
;            entry: current month 01,02,03,...,12
;            exit:  B = day-end
;
get_month_day: mov  a,month   ; get current month
               clr  c
               subb a,#10h
               jc   bcd_is_binary
               mov  a,month
               clr  c
               subb a,#06h
               sjmp convert_to_binary

bcd_is_binary: mov  a,month
convert_to_binary:  dec  a
               mov  dptr,#day_end_table
               movc a,@a+dptr
               mov  b,a
               inc  b                ; to compensate increment day before
               ret

day_end_table: dfb  31h  ; Jan
               dfb  28h  ; Feb
               dfb  31h  ; Mar
               dfb  30h  ; Apr
               dfb  31h  ; May
               dfb  30h  ; Jun
               dfb  31h  ; Jul
               dfb  31h  ; Aug
               dfb  30h  ; Sep
               dfb  31h  ; Oct
               dfb  30h  ; Nov
               dfb  31h  ; Dec



;BUFFER_ASCII CONVERT BCD IN BUFFER START $30 - $35
;         ENTRY: BCD NUMBER IN TRANSMIT BUFFER
;         EXIT: ASCII CODE IN TRANSMIT BUFFER

BUFFER_ASCII: MOV    R7,#06H
				  MOV    R0,#30H
NEXT_ASCII:	  MOV    A,@R0
				  LCALL  BCD_ASCII
				  MOV    @R0,A
				  INC    R0
				  DJNZ   R7,NEXT_ASCII
				  RET

;SEND_BUFFER SEND ASCII CODE IN TRANSMIT BUFFER TO SERIAL PORT
;         THEN DATA SEPERATOR /32/32
;         ENTRY: ASCII CODE IN TRANSMIT BUFFER
;         EXIT: NO

SEND_BUFFER: MOV     R7,#06H
				 MOV     R0,#35H
NEXT_BYTE:	 MOV     A,@R0
				 LCALL   SEND       ;SEND OUT TO SERIAL PORT
				 DEC     R0
				 DJNZ    R7,NEXT_BYTE
         lcall   cr_lf

         RET


;service_int0 activates three output port manually

service_int0: push acc
              setb 0fh
              mov  a,output
              cpl  a
              mov  p1,a
              pop  acc
              reti



;COMPARE TWO 16 BIT BINARY NUMBER
;        ENTRY: R0 FIRST OPERAND
;               R1 SECOND OPERAND
;        EXIT: C=1 FIRST OPERAND < SECOND OPERAND
;              C=0 FIRST OPERAND >= SECOND OPERAND

COMPARE:     CLR     C            ;
				 MOV     A,@R0
				 SUBB    A,@R1
				 INC     R0
				 INC     R1
				 MOV     A,@R0
				 SUBB    A,@R1
				 RET
;
;###########################################################################
;#                            MAIN PROGRAM                                 #
;###########################################################################

CURRENT_TIME_L: EQU 40H
CURRENT_TIME_H: EQU 41H
CURRENT_PROG_L: EQU 42H
CURRENT_PROG_H: EQU 43H

COUNT_L:        EQU 92h    ;7AH      ; <--- find adjust in case of oscillation
                           ; frequency is not a 3.579545 MHz
COUNT_H:        EQU 8BH    ; interrupt every 3.579545 MHz/12*(65536-29830)
                           ; = 10 Hz


MAIN_TIMER:
        MOV SP,#60H               ;  stack area start $60-$7F
        mov   light,#00h
        mov   p1,#11111111b       ; off output
        clr   serial              ;
        clr   blink
        mov   sec100,#00h
        mov   econo,#00h
        mov   tl0adj,#92h         ; for adjustment later via user calibrate
        mov  a,warm_code
        cjne a,#"%",cold_boot
        sjmp  warm_boot

cold_boot:
        mov  warm_code,#"%"
        mov  pgm_buffer,#eof       ; blank pgm at power up

        MOV  SEC,#00D
        MOV  MIN,#30H
        MOV  HOUR,#12H
        MOV  DAY,#29H
        MOV  MONTH,#04H
        MOV  YEAR,#37H
        mov  output,#00h
warm_boot:
			  SETB  EA                  ; ENABLE ALL INTERRUPT
			  SETB  ET0                 ; ENABLE TIMER 0 INTERRUPT
        setb  ex0                 ; enable external interrupt
			  MOV   TMOD,#00000001B     ; SET MODE 1 T0 (16 BIT DIVIDER)
			  LCALL INIT
        SETB  PT0                 ; TIMER 0 HIGHEST PIORITY
        MOV   DPTR,#TITLE
        LCALL SEND_STRING
        mov   th0,#count_h        ;start timer
        mov   tl0,#count_l
        setb  tr0                ;start timer

TEST10: jnb   ri,test10           ; polls receive buffer and wait command
        clr   ri
        mov   a,sbuf
        
        cjne  a,#"A",skip_modem_init     ; SKIP MODEM INITIALISED STRING
        lcall recive                    ; SEARCH "AT" STRING
        cjne  a,#"T",skip_modem_init

dummy_init:  lcall recive
        cjne  a,#cr,dummy_init          ; UNTIL END OF STRING
        sjmp  test10

skip_modem_init:

        orl   a,#20h             ; accept upper & lower
        cjne  a,#"o",com10
        sjmp  off_serial

com10:  cjne  a,#"t",com11
        sjmp  transmit_time

com11:  cjne  a,#"z",com12
        sjmp  adjust_clock

com12:  cjne  a,#"e",com13
        sjmp  set_time

com13:  cjne  a,#"d",com14
        sjmp   set_date

com14:  cjne  a,#"?",com15
        ljmp   print_com

com15:  cjne  a,#"s",com16
        ljmp   speed_up

com16:  cjne  a,#"p",com17
        ljmp   program_time


com17:  cjne   a,#"r",com18
        ljmp   read_pgm

com18:  cjne   a,#"c",com19
        ljmp   clear_io

com19:  cjne   a,#"/",com20
        ljmp   once

com20:
        lcall  send_prompt
        LJMP  TEST10

RUN2:     MOV TL0,#COUNT_L
				  MOV TH0,#COUNT_H
				  SETB TR0          ; START TIMER
				  RET


;off_serial stop transmit current date and time to terminal
off_serial:
           clr   serial
           LCALL SEND_PROMPT
           sjmp test10

;transmit_time start send current date and time to terminal
transmit_time: setb serial
               sjmp  test10

;adjust_clock change low byte of timer 0

adjust_clock: lcall cr_lf
              mov  a,tl0adj
              lcall send_ascii
              lcall cr_lf
              mov  a,#"?"
              lcall send
              lcall get_byte
              mov  tl0adj,a
              lcall send_prompt
              ljmp  test10

;set_time enter current time

set_time:     mov    dptr,#time_set
              lcall  send_string
              lcall get_byte
              mov  hour,a             ; save hour
              lcall get_byte
              mov  min,a              ; save min
              lcall get_byte
              mov  sec,a              ; save sec
              lcall  send_time
              lcall  send_prompt
              ljmp   test10

;set_date enter current date

set_date:     mov    dptr,#date_set
              lcall   send_string
              lcall  get_byte
              mov    day,a
              lcall  get_byte
              mov    month,a
              lcall  get_byte
              mov    year,a
              lcall  send_time
              lcall  send_prompt
              ljmp  test10


;print_com shows command listing

print_com:    mov    dptr,#command
              lcall  send_string
              lcall  send_prompt
              ljmp   test10

;speed_up simulate output at high speed

speed_up:     cpl    sim
              ljmp   test10


;program_time wait file from terminal write to on chip ram
;             start $30-$63 60 bytes or 20 line accepted
;             program format:
;             :01 05 2030 1 1 0 1 0 0 1 1crlf
;             :02 06 2120 1 0 0 0 1 1 0 1crlf
;             :00crlf
;     where
;             : initiate start of line
;              01 record 1,2,3,...
;                 05 date
;                    2030 time
;                         1 1 0 1 0 0 1 1 digital output
;                                        crlf end of line flag
;              00 end of record flag
;
;     maximum program storage provides 7 days, i.e. each day require four
;     byte, thus total byte is 28 bytes from $30 - $50

program_time:  clr   tr0             ; stop timer before so after program
               mov   dptr,#program   ; loading is finished actual time need
               lcall send_string     ; to be adjusted again.
               lcall  cr_lf
               mov    r0,#pgm_buffer

pgm1:          lcall  recive
               cjne   a,#":",pgm1


               lcall  get_byte         ; skip line


               cjne   a,#00h,pgm2      ; end of file detected
               sjmp   stop_pgm

pgm2:
               lcall  recive           ; skip space
               lcall  get_byte         ; get date byte
               mov    @r0,a            ; save date

               lcall  recive           ; skip space
               inc    r0

               lcall  get_byte         ; get hour byte
               mov    @r0,a            ; save hour

               inc    r0
               lcall  get_byte
               mov    @r0,a            ; save min


               inc    r0

               mov    r7,#08d          ; get control I/O bit

pgm3:          lcall  recive           ; skip space
               lcall  recive
            ;   mov    b,a
            ;   lcall  SEND_XOFF        ; pause string sending from terminal
            ;   mov    a,b
               cjne   a,#"0",pgm4
               clr    c
               sjmp   pgm5

pgm4:          setb   c
pgm5:          mov    a,@r0
               rlc    a
               mov    @r0,a
             ;  lcall  SEND_XON        ; ready to receive again
               djnz   r7,pgm3         ; loop 8 times

pgm6:          lcall  recive
               cjne   a,#lf,pgm6

               inc    r0
               sjmp   pgm1            ; read next line

stop_pgm:      mov    @r0,#eof        ; end of file
               lcall  recive
               cjne   a,#lf,stop_pgm
               mov    dptr,#finish_pgm
               lcall  send_string
               lcall  send_prompt

               setb   tr0             ; resume timer interrupt again
               ljmp   test10


;read_pgm read internal program for checking
;         reteive internal program send to terminal for checking
;         or changing current settings
     
read_pgm:      lcall  cr_lf
               mov    r0,#pgm_buffer
read2:         mov    a,@r0
               cjne   a,#eof,read3  ; until eos (0FH) found
               mov    dptr,#end_of_file
               lcall  send_string
               sjmp   read4

read3:         lcall  send_ascii    ; send day
               lcall  space
               inc    r0
               mov    a,@r0         ; get hour
               lcall  send_ascii    ; send hour
               mov    a,#":"
               lcall  send
               inc    r0
               mov    a,@r0
               lcall  send_ascii    ; send min
               lcall  space

               mov    dptr,#output_prompt
               lcall  send_string
               inc    r0
               mov    a,@r0

               mov    r7,#08h
read_io:       rlc    a
               mov    b,a
               jc     send_on
               mov    a,#"-"
               lcall  send
               sjmp   next_io_bit

send_on:       mov    a,#"O"
               lcall  send

next_io_bit:
               lcall  space
               mov    a,b
               djnz   r7,read_io

               lcall  cr_lf
               inc    r0
               sjmp   read2

read4:
               lcall  send_prompt
               ljmp   test10


;clear_io clear all 8 bit p1.0-p1.7

clear_io:      mov    output,#00000000b
               mov    p1,#11111111b       ; clear port1 also
               lcall  send_time           ; display results
               lcall  send_prompt
               ljmp   test10

;once read current time once

once:          lcall  send_time
               lcall  send_prompt
               ljmp   test10




;SEND_STRING SEND STRING CONSTANT TO TERMINAL
;            ENTRY: DPTR
;            EXIT: FOUND EOS
;
SEND_STRING: CLR   A
				 MOVC  A,@A+DPTR
				 CJNE  A,#EOS,SEND_STRING1
				 RET

SEND_STRING1: PUSH  DPL
				  PUSH  DPH
				  LCALL SEND
				  POP   DPH
				  POP   DPL
				  INC   DPTR
				  SJMP  SEND_STRING

;**********************************************************************
;         STRING CONSTANT AREA
;**********************************************************************

TITLE:    DFB  cr,lf,"Miniature Realtime Controller RTC-3707",CR,LF
          DFB        "Designed by Wichit Sirichote"
          DFB  CR,LF
PROMPT:   DFB  "& ",EOS
command:  dfb cr,lf
          dfb "o   return prompt",cr,lf
          dfb "t   send time",cr,lf
          dfb "z   adj. time base",cr,lf
          dfb "e   enter current time",cr,lf
          dfb "d   enter current date",cr,lf
          dfb "s   stroke setting",cr,lf
          dfb "p   program timer",cr,lf
          dfb "r   read program",cr,lf
          dfb "c   clear I/O",cr,lf
          dfb "/   send time once",cr,lf
          dfb "?   help command",cr,lf
          dfb eos

finish_pgm: dfb "Program stored",cr,lf,eos
program:  dfb cr,lf,"Ready to receive program",eos
output_prompt:
          dfb "OUTPUT [1..8] ",eos
time_set: dfb cr,lf,"Enter current time > ",eos
date_set: dfb cr,lf,"Enter current date > ",eos
end_of_file:   dfb "EOF",eos
WHAT?:    DFB  "WHAT?",CR,LF,EOS

				  END
